Imported Upstream version 0.10.1~dfsg1
authorJaromír Mikeš <mira.mikes@seznam.cz>
Thu, 3 Sep 2015 01:47:59 +0000 (03:47 +0200)
committerJaromír Mikeš <mira.mikes@seznam.cz>
Thu, 3 Sep 2015 01:47:59 +0000 (03:47 +0200)
279 files changed:
ChangeLog
Makefile.am
configure.ac
src/Makefile.am [deleted file]
src/channel.cpp [deleted file]
src/channel.h [deleted file]
src/conf.cpp [deleted file]
src/conf.h [deleted file]
src/const.h [deleted file]
src/core/.dirstamp [new file with mode: 0644]
src/core/channel.cpp [new file with mode: 0644]
src/core/channel.h [new file with mode: 0644]
src/core/conf.cpp [new file with mode: 0644]
src/core/conf.h [new file with mode: 0644]
src/core/const.h [new file with mode: 0644]
src/core/dataStorage.cpp [new file with mode: 0644]
src/core/dataStorage.h [new file with mode: 0644]
src/core/graphics.cpp [new file with mode: 0644]
src/core/graphics.h [new file with mode: 0644]
src/core/init.cpp [new file with mode: 0644]
src/core/init.h [new file with mode: 0644]
src/core/kernelAudio.cpp [new file with mode: 0644]
src/core/kernelAudio.h [new file with mode: 0644]
src/core/kernelMidi.cpp [new file with mode: 0644]
src/core/kernelMidi.h [new file with mode: 0644]
src/core/midiChannel.cpp [new file with mode: 0644]
src/core/midiChannel.h [new file with mode: 0644]
src/core/midiMapConf.cpp [new file with mode: 0644]
src/core/midiMapConf.h [new file with mode: 0644]
src/core/mixer.cpp [new file with mode: 0644]
src/core/mixer.h [new file with mode: 0644]
src/core/mixerHandler.cpp [new file with mode: 0644]
src/core/mixerHandler.h [new file with mode: 0644]
src/core/patch.cpp [new file with mode: 0644]
src/core/patch.h [new file with mode: 0644]
src/core/plugin.cpp [new file with mode: 0644]
src/core/plugin.h [new file with mode: 0644]
src/core/pluginHost.cpp [new file with mode: 0644]
src/core/pluginHost.h [new file with mode: 0644]
src/core/recorder.cpp [new file with mode: 0644]
src/core/recorder.h [new file with mode: 0644]
src/core/sampleChannel.cpp [new file with mode: 0644]
src/core/sampleChannel.h [new file with mode: 0644]
src/core/wave.cpp [new file with mode: 0644]
src/core/wave.h [new file with mode: 0644]
src/core/waveFx.cpp [new file with mode: 0644]
src/core/waveFx.h [new file with mode: 0644]
src/dataStorage.cpp [deleted file]
src/dataStorage.h [deleted file]
src/deps/rtaudio-mod/Makefile.in [new file with mode: 0644]
src/deps/rtaudio-mod/RtAudio.cpp [new file with mode: 0644]
src/deps/rtaudio-mod/RtAudio.h [new file with mode: 0644]
src/deps/rtaudio-mod/config/config.guess [new file with mode: 0644]
src/deps/rtaudio-mod/config/config.sub [new file with mode: 0755]
src/deps/rtaudio-mod/config/install.sh [new file with mode: 0755]
src/deps/rtaudio-mod/configure [new file with mode: 0755]
src/deps/rtaudio-mod/configure.ac [new file with mode: 0644]
src/deps/rtaudio-mod/include/FunctionDiscoveryKeys_devpkey.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/asio.cpp [new file with mode: 0644]
src/deps/rtaudio-mod/include/asio.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiodrivers.cpp [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiodrivers.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiodrvr.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiolist.cpp [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiolist.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/asiosys.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/dsound.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/ginclude.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/iasiodrv.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp [new file with mode: 0644]
src/deps/rtaudio-mod/include/iasiothiscallresolver.h [new file with mode: 0644]
src/deps/rtaudio-mod/include/soundcard.h [new file with mode: 0644]
src/deps/rtaudio-mod/librtaudio.pc [new file with mode: 0644]
src/deps/rtaudio-mod/librtaudio.pc.in [new file with mode: 0644]
src/deps/rtaudio-mod/rtaudio-config [new file with mode: 0755]
src/deps/rtaudio-mod/rtaudio-config.in [new file with mode: 0644]
src/deps/rtaudio-mod/tests/Makefile.in [new file with mode: 0644]
src/deps/vst/aeffect.h [new file with mode: 0644]
src/deps/vst/aeffectx.h [new file with mode: 0644]
src/deps/vst/vstfxstore.h [new file with mode: 0644]
src/ext/giada.ico [new file with mode: 0644]
src/ext/resource.h [new file with mode: 0644]
src/ext/resource.rc [new file with mode: 0644]
src/gd_about.cpp [deleted file]
src/gd_about.h [deleted file]
src/gd_actionEditor.cpp [deleted file]
src/gd_actionEditor.h [deleted file]
src/gd_beatsInput.cpp [deleted file]
src/gd_beatsInput.h [deleted file]
src/gd_bpmInput.cpp [deleted file]
src/gd_bpmInput.h [deleted file]
src/gd_browser.cpp [deleted file]
src/gd_browser.h [deleted file]
src/gd_config.cpp [deleted file]
src/gd_config.h [deleted file]
src/gd_devInfo.cpp [deleted file]
src/gd_devInfo.h [deleted file]
src/gd_editor.cpp [deleted file]
src/gd_editor.h [deleted file]
src/gd_keyGrabber.cpp [deleted file]
src/gd_keyGrabber.h [deleted file]
src/gd_mainWindow.cpp [deleted file]
src/gd_mainWindow.h [deleted file]
src/gd_midiInput.cpp [deleted file]
src/gd_midiInput.h [deleted file]
src/gd_midiOutput.cpp [deleted file]
src/gd_midiOutput.h [deleted file]
src/gd_pluginList.cpp [deleted file]
src/gd_pluginList.h [deleted file]
src/gd_pluginWindow.cpp [deleted file]
src/gd_pluginWindow.h [deleted file]
src/gd_pluginWindowGUI.cpp [deleted file]
src/gd_pluginWindowGUI.h [deleted file]
src/gd_warnings.cpp [deleted file]
src/gd_warnings.h [deleted file]
src/ge_actionChannel.cpp [deleted file]
src/ge_actionChannel.h [deleted file]
src/ge_actionWidget.cpp [deleted file]
src/ge_actionWidget.h [deleted file]
src/ge_browser.cpp [deleted file]
src/ge_browser.h [deleted file]
src/ge_channel.cpp [deleted file]
src/ge_channel.h [deleted file]
src/ge_column.cpp [deleted file]
src/ge_column.h [deleted file]
src/ge_envelopeChannel.cpp [deleted file]
src/ge_envelopeChannel.h [deleted file]
src/ge_midiChannel.cpp [deleted file]
src/ge_midiChannel.h [deleted file]
src/ge_midiIoTools.cpp [deleted file]
src/ge_midiIoTools.h [deleted file]
src/ge_mixed.cpp [deleted file]
src/ge_mixed.h [deleted file]
src/ge_muteChannel.cpp [deleted file]
src/ge_muteChannel.h [deleted file]
src/ge_pianoRoll.cpp [deleted file]
src/ge_pianoRoll.h [deleted file]
src/ge_sampleChannel.cpp [deleted file]
src/ge_sampleChannel.h [deleted file]
src/ge_waveform.cpp [deleted file]
src/ge_waveform.h [deleted file]
src/ge_window.cpp [deleted file]
src/ge_window.h [deleted file]
src/gg_keyboard.cpp [deleted file]
src/gg_keyboard.h [deleted file]
src/gg_waveTools.cpp [deleted file]
src/gg_waveTools.h [deleted file]
src/giada.ico [deleted file]
src/glue.cpp [deleted file]
src/glue.h [deleted file]
src/glue/glue.cpp [new file with mode: 0644]
src/glue/glue.h [new file with mode: 0644]
src/graphics.cpp [deleted file]
src/graphics.h [deleted file]
src/gui/dialogs/gd_about.cpp [new file with mode: 0644]
src/gui/dialogs/gd_about.h [new file with mode: 0644]
src/gui/dialogs/gd_actionEditor.cpp [new file with mode: 0644]
src/gui/dialogs/gd_actionEditor.h [new file with mode: 0644]
src/gui/dialogs/gd_beatsInput.cpp [new file with mode: 0644]
src/gui/dialogs/gd_beatsInput.h [new file with mode: 0644]
src/gui/dialogs/gd_bpmInput.cpp [new file with mode: 0644]
src/gui/dialogs/gd_bpmInput.h [new file with mode: 0644]
src/gui/dialogs/gd_browser.cpp [new file with mode: 0644]
src/gui/dialogs/gd_browser.h [new file with mode: 0644]
src/gui/dialogs/gd_config.cpp [new file with mode: 0644]
src/gui/dialogs/gd_config.h [new file with mode: 0644]
src/gui/dialogs/gd_devInfo.cpp [new file with mode: 0644]
src/gui/dialogs/gd_devInfo.h [new file with mode: 0644]
src/gui/dialogs/gd_editor.cpp [new file with mode: 0644]
src/gui/dialogs/gd_editor.h [new file with mode: 0644]
src/gui/dialogs/gd_keyGrabber.cpp [new file with mode: 0644]
src/gui/dialogs/gd_keyGrabber.h [new file with mode: 0644]
src/gui/dialogs/gd_mainWindow.cpp [new file with mode: 0644]
src/gui/dialogs/gd_mainWindow.h [new file with mode: 0644]
src/gui/dialogs/gd_midiInput.cpp [new file with mode: 0644]
src/gui/dialogs/gd_midiInput.h [new file with mode: 0644]
src/gui/dialogs/gd_midiOutput.cpp [new file with mode: 0644]
src/gui/dialogs/gd_midiOutput.h [new file with mode: 0644]
src/gui/dialogs/gd_pluginList.cpp [new file with mode: 0644]
src/gui/dialogs/gd_pluginList.h [new file with mode: 0644]
src/gui/dialogs/gd_pluginWindow.cpp [new file with mode: 0644]
src/gui/dialogs/gd_pluginWindow.h [new file with mode: 0644]
src/gui/dialogs/gd_pluginWindowGUI.cpp [new file with mode: 0644]
src/gui/dialogs/gd_pluginWindowGUI.h [new file with mode: 0644]
src/gui/dialogs/gd_warnings.cpp [new file with mode: 0644]
src/gui/dialogs/gd_warnings.h [new file with mode: 0644]
src/gui/elems/ge_actionChannel.cpp [new file with mode: 0644]
src/gui/elems/ge_actionChannel.h [new file with mode: 0644]
src/gui/elems/ge_actionWidget.cpp [new file with mode: 0644]
src/gui/elems/ge_actionWidget.h [new file with mode: 0644]
src/gui/elems/ge_browser.cpp [new file with mode: 0644]
src/gui/elems/ge_browser.h [new file with mode: 0644]
src/gui/elems/ge_channel.cpp [new file with mode: 0644]
src/gui/elems/ge_channel.h [new file with mode: 0644]
src/gui/elems/ge_channelButton.cpp [new file with mode: 0644]
src/gui/elems/ge_channelButton.h [new file with mode: 0644]
src/gui/elems/ge_column.cpp [new file with mode: 0644]
src/gui/elems/ge_column.h [new file with mode: 0644]
src/gui/elems/ge_controller.cpp [new file with mode: 0644]
src/gui/elems/ge_controller.h [new file with mode: 0644]
src/gui/elems/ge_envelopeChannel.cpp [new file with mode: 0644]
src/gui/elems/ge_envelopeChannel.h [new file with mode: 0644]
src/gui/elems/ge_keyboard.cpp [new file with mode: 0644]
src/gui/elems/ge_keyboard.h [new file with mode: 0644]
src/gui/elems/ge_midiChannel.cpp [new file with mode: 0644]
src/gui/elems/ge_midiChannel.h [new file with mode: 0644]
src/gui/elems/ge_midiIoTools.cpp [new file with mode: 0644]
src/gui/elems/ge_midiIoTools.h [new file with mode: 0644]
src/gui/elems/ge_mixed.cpp [new file with mode: 0644]
src/gui/elems/ge_mixed.h [new file with mode: 0644]
src/gui/elems/ge_modeBox.cpp [new file with mode: 0644]
src/gui/elems/ge_modeBox.h [new file with mode: 0644]
src/gui/elems/ge_muteChannel.cpp [new file with mode: 0644]
src/gui/elems/ge_muteChannel.h [new file with mode: 0644]
src/gui/elems/ge_pianoRoll.cpp [new file with mode: 0644]
src/gui/elems/ge_pianoRoll.h [new file with mode: 0644]
src/gui/elems/ge_sampleChannel.cpp [new file with mode: 0644]
src/gui/elems/ge_sampleChannel.h [new file with mode: 0644]
src/gui/elems/ge_status.cpp [new file with mode: 0644]
src/gui/elems/ge_status.h [new file with mode: 0644]
src/gui/elems/ge_waveTools.cpp [new file with mode: 0644]
src/gui/elems/ge_waveTools.h [new file with mode: 0644]
src/gui/elems/ge_waveform.cpp [new file with mode: 0644]
src/gui/elems/ge_waveform.h [new file with mode: 0644]
src/gui/elems/ge_window.cpp [new file with mode: 0644]
src/gui/elems/ge_window.h [new file with mode: 0644]
src/gui_utils.cpp [deleted file]
src/gui_utils.h [deleted file]
src/init.cpp [deleted file]
src/init.h [deleted file]
src/kernelAudio.cpp [deleted file]
src/kernelAudio.h [deleted file]
src/kernelMidi.cpp [deleted file]
src/kernelMidi.h [deleted file]
src/log.cpp [deleted file]
src/log.h [deleted file]
src/main.cpp
src/midiChannel.cpp [deleted file]
src/midiChannel.h [deleted file]
src/midiMapConf.cpp [deleted file]
src/midiMapConf.h [deleted file]
src/mixer.cpp [deleted file]
src/mixer.h [deleted file]
src/mixerHandler.cpp [deleted file]
src/mixerHandler.h [deleted file]
src/patch.cpp [deleted file]
src/patch.h [deleted file]
src/plugin.cpp [deleted file]
src/plugin.h [deleted file]
src/pluginHost.cpp [deleted file]
src/pluginHost.h [deleted file]
src/recorder.cpp [deleted file]
src/recorder.h [deleted file]
src/resource.h [deleted file]
src/resource.rc [deleted file]
src/rtaudio-mod/Makefile.in [deleted file]
src/rtaudio-mod/RtAudio.cpp [deleted file]
src/rtaudio-mod/RtAudio.h [deleted file]
src/rtaudio-mod/config/config.guess [deleted file]
src/rtaudio-mod/config/config.sub [deleted file]
src/rtaudio-mod/config/install.sh [deleted file]
src/rtaudio-mod/configure [deleted file]
src/rtaudio-mod/configure.ac [deleted file]
src/rtaudio-mod/librtaudio.pc.in [deleted file]
src/rtaudio-mod/rtaudio-config.in [deleted file]
src/sampleChannel.cpp [deleted file]
src/sampleChannel.h [deleted file]
src/utils.cpp [deleted file]
src/utils.h [deleted file]
src/utils/gui_utils.cpp [new file with mode: 0644]
src/utils/gui_utils.h [new file with mode: 0644]
src/utils/log.cpp [new file with mode: 0644]
src/utils/log.h [new file with mode: 0644]
src/utils/utils.cpp [new file with mode: 0644]
src/utils/utils.h [new file with mode: 0644]
src/wave.cpp [deleted file]
src/wave.h [deleted file]
src/waveFx.cpp [deleted file]
src/waveFx.h [deleted file]

index b662cd6b144c0ce724c7d0f1a7459b4db881edc6..b38ea269340c35961b0b757510a34a5c5d1c8619 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
 
 
+0.10.1 --- 2015 . ? . ?
+- Remove support for patches created with Giada < 0.6.x
+- Massive source folders refactoring
+- Improved usability of "play" buttons for channels
+- Fix check for configured soundsystem (would break compilation on g++5)
+- Small fixes and cleanup in Makefile.am
+
+
 0.10.0 --- 2015 . 07 . 05
 - MIDI lightning output
 - Other minor fixes
index e1c45f3051cb4536176503057211047b451f7d0c..16a06853a5b8e7e0ea1b21785d7e30cd9aa9e257 100644 (file)
@@ -1 +1,194 @@
-SUBDIRS=src
\ No newline at end of file
+AUTOMAKE_OPTIONS = foreign
+
+AM_CXXFLAGS = -Wall -pedantic -Werror
+
+bin_PROGRAMS = giada
+
+giada_SOURCES =                        \
+src/main.cpp                           \
+src/core/const.h                       \
+src/core/channel.h                     \
+src/core/channel.cpp                   \
+src/core/sampleChannel.h               \
+src/core/sampleChannel.cpp             \
+src/core/midiChannel.h                 \
+src/core/midiChannel.cpp               \
+src/core/midiMapConf.h                 \
+src/core/midiMapConf.cpp               \
+src/core/conf.h                        \
+src/core/conf.cpp                      \
+src/core/kernelAudio.h                 \
+src/core/kernelAudio.cpp               \
+src/core/pluginHost.h                               \
+src/core/pluginHost.cpp                \
+src/core/mixerHandler.h                \
+src/core/mixerHandler.cpp              \
+src/core/init.h                        \
+src/core/init.cpp                      \
+src/core/plugin.h                      \
+src/core/plugin.cpp                    \
+src/core/wave.h                        \
+src/core/wave.cpp                      \
+src/core/waveFx.h                      \
+src/core/waveFx.cpp                    \
+src/core/kernelMidi.h                  \
+src/core/kernelMidi.cpp                \
+src/core/graphics.h                    \
+src/core/graphics.cpp                  \
+src/core/patch.h                       \
+src/core/patch.cpp                     \
+src/core/recorder.h                    \
+src/core/recorder.cpp                  \
+src/core/mixer.h                       \
+src/core/mixer.cpp                     \
+src/core/dataStorage.h                \
+src/core/dataStorage.cpp               \
+src/glue/glue.h                        \
+src/glue/glue.cpp                      \
+src/gui/dialogs/gd_keyGrabber.h        \
+src/gui/dialogs/gd_keyGrabber.cpp      \
+src/gui/dialogs/gd_about.h             \
+src/gui/dialogs/gd_about.cpp           \
+src/gui/dialogs/gd_mainWindow.h        \
+src/gui/dialogs/gd_mainWindow.cpp      \
+src/gui/dialogs/gd_beatsInput.h        \
+src/gui/dialogs/gd_beatsInput.cpp      \
+src/gui/dialogs/gd_warnings.h          \
+src/gui/dialogs/gd_warnings.cpp        \
+src/gui/dialogs/gd_bpmInput.h          \
+src/gui/dialogs/gd_bpmInput.cpp        \
+src/gui/dialogs/gd_browser.h           \
+src/gui/dialogs/gd_browser.cpp         \
+src/gui/dialogs/gd_config.h                             \
+src/gui/dialogs/gd_config.cpp          \
+src/gui/dialogs/gd_devInfo.h           \
+src/gui/dialogs/gd_devInfo.cpp              \
+src/gui/dialogs/gd_pluginList.h               \
+src/gui/dialogs/gd_pluginList.cpp      \
+src/gui/dialogs/gd_pluginWindow.h           \
+src/gui/dialogs/gd_pluginWindow.cpp    \
+src/gui/dialogs/gd_editor.h            \
+src/gui/dialogs/gd_editor.cpp          \
+src/gui/dialogs/gd_pluginWindowGUI.h   \
+src/gui/dialogs/gd_pluginWindowGUI.cpp \
+src/gui/dialogs/gd_midiOutput.h        \
+src/gui/dialogs/gd_midiOutput.cpp      \
+src/gui/dialogs/gd_midiInput.h         \
+src/gui/dialogs/gd_midiInput.cpp       \
+src/gui/dialogs/gd_actionEditor.h           \
+src/gui/dialogs/gd_actionEditor.cpp    \
+src/gui/elems/ge_column.h              \
+src/gui/elems/ge_column.cpp            \
+src/gui/elems/ge_sampleChannel.h       \
+src/gui/elems/ge_sampleChannel.cpp     \
+src/gui/elems/ge_midiChannel.h         \
+src/gui/elems/ge_midiChannel.cpp       \
+src/gui/elems/ge_midiIoTools.h         \
+src/gui/elems/ge_midiIoTools.cpp       \
+src/gui/elems/ge_mixed.h               \
+src/gui/elems/ge_mixed.cpp             \
+src/gui/elems/ge_waveform.h            \
+src/gui/elems/ge_waveform.cpp          \
+src/gui/elems/ge_browser.h                      \
+src/gui/elems/ge_browser.cpp           \
+src/gui/elems/ge_actionWidget.h        \
+src/gui/elems/ge_actionWidget.cpp      \
+src/gui/elems/ge_envelopeChannel.h     \
+src/gui/elems/ge_envelopeChannel.cpp   \
+src/gui/elems/ge_pianoRoll.h                  \
+src/gui/elems/ge_pianoRoll.cpp         \
+src/gui/elems/ge_channel.h             \
+src/gui/elems/ge_channel.cpp           \
+src/gui/elems/ge_muteChannel.h         \
+src/gui/elems/ge_muteChannel.cpp       \
+src/gui/elems/ge_actionChannel.h       \
+src/gui/elems/ge_actionChannel.cpp     \
+src/gui/elems/ge_window.h                               \
+src/gui/elems/ge_window.cpp            \
+src/gui/elems/ge_status.h              \
+src/gui/elems/ge_status.cpp            \
+src/gui/elems/ge_keyboard.h            \
+src/gui/elems/ge_keyboard.cpp          \
+src/gui/elems/ge_waveTools.h           \
+src/gui/elems/ge_waveTools.cpp         \
+src/gui/elems/ge_modeBox.h             \
+src/gui/elems/ge_modeBox.cpp           \
+src/gui/elems/ge_controller.h          \
+src/gui/elems/ge_controller.cpp        \
+src/gui/elems/ge_channelButton.h       \
+src/gui/elems/ge_channelButton.cpp     \
+src/utils/log.h                        \
+src/utils/log.cpp                      \
+src/utils/gui_utils.h                  \
+src/utils/gui_utils.cpp                \
+src/utils/utils.h                      \
+src/utils/utils.cpp
+
+# Check for environment: these vars are defined via AM_CONDITIONAL
+# inside configure.ac
+
+if LINUX
+giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm \
+                                                       src/deps/rtaudio-mod/librtaudio.a -ljack -lasound -lpthread -ldl \
+                                                       -lpulse-simple -lpulse -lsamplerate -lrtmidi
+#giada_LDFLAGS = -DWITH_VST
+endif
+if WINDOWS
+giada_LDADD   = -lrtaudio -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \
+                -lshell32 -lvfw32 -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 \
+                -lsndfile -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser \
+                -lpthreadGC2
+giada_LDFLAGS = -mwindows -static
+giada_SOURCES += resource.rc
+endif
+if OSX
+giada_LDADD    = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \
+                                                                -lsamplerate
+giada_CXXFLAGS = -m32
+giada_LDFLAGS  = -m32 -framework CoreAudio -framework Cocoa -framework Carbon \
+                -framework CoreMIDI -framework CoreFoundation
+endif
+
+
+# used only under MinGW to compile the resource.rc file (program icon)
+
+resource.o:
+       windres src/ext/resource.rc -o resource.o 
+
+
+#compile libraries
+
+#libs:
+#if LINUX
+#      @cd rtaudio-mod; echo "Building RtAudio for Linux..."; \
+#      ./configure --with-jack --with-alsa --with-pulse; \
+#      make;
+#endif
+#if WINDOWS
+#      echo "Building RtAudio for Windows: nothing to do"
+#endif
+#if OSX
+#      @cd rtaudio-mod; echo "Building RtAudio for OS X..."; \
+#      ./configure --with-core; \
+#      make;
+#endif
+
+src/deps/rtaudio-mod/librtaudio.a:
+       @cd src/deps/rtaudio-mod; echo "Building RtAudio for Linux..."; \
+       ./configure --with-jack --with-alsa --with-pulse; \
+       make;
+
+# rename the binaries
+
+if LINUX
+rename:
+       mv giada giada_lin
+endif
+if WINDOWS
+rename:
+       mv giada giada_win.exe
+endif
+if OSX
+rename:
+       mv giada giada_osx
+endif
index 5bb3b5979cae6f40aa978830bec36f5e6da15671..a501966047ef17c441c6a8db95cf2f89d1f2a61c 100644 (file)
@@ -6,9 +6,9 @@
 AC_PREREQ(2.60)
 AC_INIT([giada], [0.10], [giadaloopmachine@gmail.com])
 AC_CONFIG_SRCDIR([src/main.cpp])
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([subdir-objects])
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # test the build environment. These vars are used in Makefile.am during
 # the linking of the libraries.
@@ -36,7 +36,7 @@ AM_CONDITIONAL(LINUX,   test "x$os" = "xlinux")
 AM_CONDITIONAL(WINDOWS, test "x$os" = "xwindows")
 AM_CONDITIONAL(OSX,     test "x$os" = "xosx")
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # --enable-vst. VST compilation is disabled by default
 #
@@ -54,16 +54,21 @@ AC_ARG_ENABLE(
   [AC_DEFINE(WITH_VST)]
 )
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
-# Check for programs.
+# Check for C++ compiler
 
 AC_PROG_CXX
+
+# Check for C compiler (TODO - is that really needed?)
+
 AC_PROG_CC
-AC_PROG_INSTALL
+
+# Check for make
+
 AC_PROG_MAKE_SET
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # Check for libraries.
 
@@ -74,7 +79,7 @@ AC_CHECK_LIB(
        [AC_MSG_ERROR([error: library 'pthread' not found!])]
 )
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # Check for generic headers (fltk, rtaudio and libsndfile are static,
 # we ask if headers are available)
@@ -138,30 +143,12 @@ else
 fi
 
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # Check for linux header files.
 
 if test "x$os" = "xlinux"; then
 
-# TODO
-
-#      AC_LANG_PUSH([C++])
-#      AC_CHECK_HEADER(
-#              [X11/extensions/Xext.h],
-#              [],
-#              [AC_MSG_ERROR([missing Xext.h, maybe you need to install the libxext-dev package?])]
-#      )
-#      AC_LANG_POP
-
-#      AC_LANG_PUSH([C++])
-#      AC_CHECK_HEADER(
-#              [X11/Xft.h],
-#              [],
-#              [AC_MSG_ERROR([missing Xft.h, maybe you need to install the libxft-dev package?])]
-#      )
-#      AC_LANG_POP
-
        AC_LANG_PUSH([C++])
        AC_CHECK_HEADER(
                [X11/xpm.h],
@@ -171,9 +158,9 @@ if test "x$os" = "xlinux"; then
        AC_LANG_POP
 fi
 
-# ----------------------------------------------------------------------
+# ------------------------------------------------------------------------------
 
 # finalizing
 
-AC_CONFIG_FILES([Makefile src/Makefile])
+AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644 (file)
index a717df4..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-
-
-# aeffect.h (header from VST SDK) uses 'long long' which is not supported
-# in ISO C++ 1998 and -Werror flag breaks the compilation.
-# This is a workaround, fixes needed.
-
-if WINDOWS
-AM_CXXFLAGS = -Wall -pedantic
-else
-AM_CXXFLAGS = -Wall -pedantic -Werror
-endif
-
-bin_PROGRAMS = giada
-
-giada_SOURCES = \
-const.h              gd_keyGrabber.h        glue.h               mixerHandler.cpp \
-gd_about.cpp         gd_mainWindow.cpp      graphics.cpp         mixerHandler.h \
-gd_about.h           gd_mainWindow.h        graphics.h           patch.cpp \
-gd_beatsInput.cpp    gd_warnings.cpp        ge_mixed.cpp         patch.h \
-gd_beatsInput.h      gd_warnings.h          ge_mixed.h           recorder.cpp \
-gd_bpmInput.cpp      ge_waveform.cpp        gui_utils.cpp        recorder.h \
-gd_bpmInput.h        ge_waveform.h          gui_utils.h          utils.cpp \
-gd_browser.cpp       init.cpp               channel.h            utils.h \
-gd_browser.h         init.h                                    gd_config.cpp        channel.cpp \
-gg_keyboard.cpp      kernelAudio.cpp        wave.cpp            gd_config.h \
-gg_keyboard.h        kernelAudio.h          waveFx.cpp                        gd_editor.cpp \
-gg_waveTools.cpp     main.cpp               waveFx.h                                gd_editor.h \
-gg_waveTools.h       mixer.cpp              wave.h                                  gd_keyGrabber.cpp \
-glue.cpp             mixer.h                                               ge_browser.h                     ge_browser.cpp \
-gd_devInfo.cpp            gd_devInfo.h           plugin.h             plugin.cpp \
-pluginHost.h                      pluginHost.cpp         gd_pluginList.h            gd_pluginList.cpp \
-gd_pluginWindow.h         gd_pluginWindow.cpp    ge_window.h                        ge_window.cpp \
-dataStorage.h                     dataStorage.cpp                  conf.h                                           conf.cpp \
-gd_actionEditor.h         gd_actionEditor.cpp    ge_muteChannel.h     ge_muteChannel.cpp \
-ge_actionChannel.h   ge_actionChannel.cpp   gd_pluginWindowGUI.h gd_pluginWindowGUI.cpp \
-ge_actionWidget.h    ge_actionWidget.cpp    ge_envelopeChannel.h ge_envelopeChannel.cpp \
-ge_pianoRoll.h            ge_pianoRoll.cpp       kernelMidi.h         kernelMidi.cpp \
-gd_midiOutput.h      gd_midiOutput.cpp      gd_midiInput.h       gd_midiInput.cpp \
-sampleChannel.h      sampleChannel.cpp      midiChannel.cpp      midiChannel.h \
-midiMapConf.cpp      midiMapConf.h          ge_channel.h         ge_channel.cpp \
-log.h                log.cpp                ge_column.h          ge_column.cpp \
-ge_sampleChannel.h   ge_sampleChannel.cpp   ge_midiChannel.h     ge_midiChannel.cpp \
-ge_midiIoTools.h     ge_midiIoTools.cpp
-
-
-
-# Check for environment: these vars are defined via AM_CONDITIONAL
-# inside configure.ac
-
-if LINUX
-giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm \
-                                                       rtaudio-mod/librtaudio.a -ljack -lasound -lpthread -ldl \
-                                                       -lpulse-simple -lpulse -lsamplerate -lrtmidi
-endif
-if WINDOWS
-giada_LDADD   = -lrtaudio -ldsound -lwsock32 -lm -lpthread \
-                                                               -lfltk -lwininet -lgdi32 -lshell32 -lvfw32 -lrpcrt4 \
-                                                               -luuid -lcomctl32 -lole32 -lws2_32 -lsndfile \
-                                                               -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser
-giada_LDFLAGS = -mwindows -mno-cygwin -static
-giada_SOURCES += resource.rc
-endif
-if OSX
-giada_LDADD   = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \
-                                                               -lsamplerate
-giada_LDFLAGS = -framework CoreAudio -framework Cocoa -framework Carbon \
-                -framework CoreMIDI -framework CoreFoundation
-endif
-
-
-# used only under MinGW to compile the resource.rc file (program icon)
-
-.rc.o:
-       windres $^ -o $@
-%.o : %.rc
-       windres $^ -o $@
-
-
-
-#compile libraries
-
-libs:
-if LINUX
-       @cd rtaudio-mod; echo "Building RtAudio for Linux..."; \
-       ./configure --with-jack --with-alsa --with-pulse; \
-       make;
-endif
-if WINDOWS
-       @cd rtaudio-mod; echo "Building RtAudio for Windows..."; \
-       ./configure --with-asio --with-ds; \
-       make;
-endif
-if OSX
-       @cd rtaudio-mod; echo "Building RtAudio for OS X..."; \
-       ./configure --with-core; \
-       make;
-endif
-
-
-
-# rename the binaries
-
-if LINUX
-rename:
-       mv giada giada_lin
-endif
-if WINDOWS
-rename:
-       mv giada giada_win.exe
-endif
-if OSX
-rename:
-       mv giada giada_osx
-endif
diff --git a/src/channel.cpp b/src/channel.cpp
deleted file mode 100644 (file)
index 6c4c48e..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "channel.h"
-#include "pluginHost.h"
-#include "kernelMidi.h"
-#include "patch.h"
-#include "wave.h"
-#include "mixer.h"
-#include "mixerHandler.h"
-#include "conf.h"
-#include "waveFx.h"
-#include "log.h"
-#include "midiMapConf.h"
-#include "ge_channel.h"
-
-
-extern Patch       G_Patch;
-extern Mixer       G_Mixer;
-extern Conf        G_Conf;
-extern MidiMapConf G_MidiMap;
-#ifdef WITH_VST
-extern PluginHost  G_PluginHost;
-#endif
-
-
-Channel::Channel(int type, int status, int bufferSize)
-       : bufferSize(bufferSize),
-         type      (type),
-               status    (status),
-               key       (0),
-         volume    (DEFAULT_VOL),
-         volume_i  (1.0f),
-         volume_d  (0.0f),
-         panLeft   (1.0f),
-         panRight  (1.0f),
-         mute_i    (false),
-         mute_s    (false),
-         mute      (false),
-         solo      (false),
-         hasActions(false),
-         recStatus (REC_STOPPED),
-         vChan     (NULL),
-         guiChannel(NULL),
-         midiIn         (true),
-         midiInKeyPress (0x0),
-         midiInKeyRel   (0x0),
-         midiInKill     (0x0),
-         midiInVolume   (0x0),
-         midiInMute     (0x0),
-         midiInSolo     (0x0),
-         midiOutL       (false),
-         midiOutLplaying(0x0),
-         midiOutLmute   (0x0),
-         midiOutLsolo   (0x0)
-{
-       vChan = (float *) malloc(bufferSize * sizeof(float));
-       if (!vChan)
-               gLog("[Channel] unable to alloc memory for vChan\n");
-       memset(vChan, 0, bufferSize * sizeof(float));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Channel::~Channel()
-{
-       status = STATUS_OFF;
-       if (vChan)
-               free(vChan);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset)
-{
-       gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
-               learn, chan, msg, offset);
-
-       uint32_t out;
-
-       /* isolate 'channel' from learnt message and offset it as requested by 'nn'
-        * in the midimap configuration file. */
-
-       out  = ((learn & 0x00FF0000) >> 16) << offset;
-
-       /* merge the previously prepared channel into final message, and finally
-        * send it. */
-
-       out |= msg | (chan << 24);
-       kernelMidi::send(out);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::readPatchMidiIn(int i)
-{
-       midiIn         = G_Patch.getMidiValue(i, "In");
-       midiInKeyPress = G_Patch.getMidiValue(i, "InKeyPress");
-       midiInKeyRel   = G_Patch.getMidiValue(i, "InKeyRel");
-  midiInKill     = G_Patch.getMidiValue(i, "InKill");
-  midiInVolume   = G_Patch.getMidiValue(i, "InVolume");
-  midiInMute     = G_Patch.getMidiValue(i, "InMute");
-  midiInSolo     = G_Patch.getMidiValue(i, "InSolo");
-}
-
-void Channel::readPatchMidiOut(int i)
-{
-       midiOutL        = G_Patch.getMidiValue(i, "OutL");
-       midiOutLplaying = G_Patch.getMidiValue(i, "OutLplaying");
-       midiOutLmute    = G_Patch.getMidiValue(i, "OutLmute");
-       midiOutLsolo    = G_Patch.getMidiValue(i, "OutLsolo");
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool Channel::isPlaying()
-{
-       return status & (STATUS_PLAY | STATUS_ENDING);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::writePatch(FILE *fp, int i, bool isProject)
-{
-       fprintf(fp, "chanType%d=%d\n",     i, type);
-       fprintf(fp, "chanIndex%d=%d\n",    i, index);
-       fprintf(fp, "chanColumn%d=%d\n",   i, guiChannel->getColumnIndex());
-       fprintf(fp, "chanMute%d=%d\n",     i, mute);
-       fprintf(fp, "chanMute_s%d=%d\n",   i, mute_s);
-       fprintf(fp, "chanSolo%d=%d\n",     i, solo);
-       fprintf(fp, "chanvol%d=%f\n",      i, volume);
-       fprintf(fp, "chanPanLeft%d=%f\n",  i, panLeft);
-       fprintf(fp, "chanPanRight%d=%f\n", i, panRight);
-
-       fprintf(fp, "chanMidiIn%d=%u\n",         i, midiIn);
-       fprintf(fp, "chanMidiInKeyPress%d=%u\n", i, midiInKeyPress);
-       fprintf(fp, "chanMidiInKeyRel%d=%u\n",   i, midiInKeyRel);
-       fprintf(fp, "chanMidiInKill%d=%u\n",     i, midiInKill);
-       fprintf(fp, "chanMidiInVolume%d=%u\n",   i, midiInVolume);
-       fprintf(fp, "chanMidiInMute%d=%u\n",     i, midiInMute);
-       fprintf(fp, "chanMidiInSolo%d=%u\n",     i, midiInSolo);
-
-       fprintf(fp, "chanMidiOutL%d=%u\n",        i, midiOutL);
-       fprintf(fp, "chanMidiOutLplaying%d=%u\n", i, midiOutLplaying);
-       fprintf(fp, "chanMidiOutLmute%d=%u\n",    i, midiOutLmute);
-       fprintf(fp, "chanMidiOutLsolo%d=%u\n",    i, midiOutLsolo);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::sendMidiLmute()
-{
-       if (!midiOutL || midiOutLmute == 0x0)
-               return;
-       if (mute)
-               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOnChan, G_MidiMap.muteOnMsg, G_MidiMap.muteOnOffset);
-       else
-               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOffChan, G_MidiMap.muteOffMsg, G_MidiMap.muteOffOffset);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::sendMidiLsolo()
-{
-       if (!midiOutL || midiOutLsolo == 0x0)
-               return;
-       if (solo)
-               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOnChan, G_MidiMap.soloOnMsg, G_MidiMap.soloOnOffset);
-       else
-               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOffChan, G_MidiMap.soloOffMsg, G_MidiMap.soloOffOffset);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::sendMidiLplay()
-{
-       if (!midiOutL || midiOutLplaying == 0x0)
-               return;
-       switch (status) {
-               case STATUS_OFF:
-                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppedChan, G_MidiMap.stoppedMsg, G_MidiMap.stoppedOffset);
-                       break;
-               case STATUS_PLAY:
-                       sendMidiLmessage(midiOutLplaying, G_MidiMap.playingChan, G_MidiMap.playingMsg, G_MidiMap.playingOffset);
-                       break;
-               case STATUS_WAIT:
-                       sendMidiLmessage(midiOutLplaying, G_MidiMap.waitingChan, G_MidiMap.waitingMsg, G_MidiMap.waitingOffset);
-                       break;
-               case STATUS_ENDING:
-                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppingChan, G_MidiMap.stoppingMsg, G_MidiMap.stoppingOffset);
-       }
-}
diff --git a/src/channel.h b/src/channel.h
deleted file mode 100644 (file)
index fa34eac..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef CHANNEL_H
-#define CHANNEL_H
-
-
-#include "utils.h"
-#include "const.h"
-#include "recorder.h"
-
-
-#ifdef WITH_VST
-
-/* before including aeffetx(x).h we must define __cdecl, otherwise VST
- * headers can't be compiled correctly. In windows __cdecl is already
- * defined. */
-
-       #ifdef __GNUC__
-               #ifndef _WIN32
-                       #define __cdecl
-               #endif
-       #endif
-       #include "vst/aeffectx.h"
-
-#endif
-
-
-class Channel {
-
-protected:
-
-       /* bufferSize
-        * size of every buffer in this channel (vChan, pChan) */
-
-       int bufferSize;
-
-       /* sendMidiLMessage
-        * compose a MIDI message by merging bytes from MidiMap conf class, and send
-        * it to KernelMidi. */
-
-       void sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset);
-
-public:
-
-       Channel(int type, int status, int bufferSize);
-       virtual ~Channel();
-
-       /* writePatch
-        * store values in patch, writing to *fp. */
-
-       virtual void writePatch(FILE *fp, int i, bool isProject);
-
-       /* loadByPatch
-        * load a sample inside a patch. */
-
-       virtual int loadByPatch(const char *file, int i) = 0;
-
-       /* process
-        * merge vChannels into buffer, plus plugin processing (if any). */
-
-       virtual void process(float *buffer) = 0;
-
-       /* start
-        * action to do when channel starts. doQuantize = false (don't
-        * quantize) when Mixer is reading actions from Recorder::. */
-
-       virtual void start(int frame, bool doQuantize) = 0;
-
-       /* stop
-        * action to do when channel is stopped normally (via key or MIDI). */
-
-       virtual void stop() = 0;
-
-       /* kill
-        * action to do when channel stops abruptly. */
-
-       virtual void kill(int frame) = 0;
-
-       /* mute
-        * action to do when channel is muted. If internal == true, set
-        * internal mute without altering main mute. */
-
-       virtual void setMute  (bool internal) = 0;
-       virtual void unsetMute(bool internal) = 0;
-
-       /* empty
-        * free any associated resources (e.g. waveform for SAMPLE). */
-
-       virtual void empty() = 0;
-
-       /* stopBySeq
-        * action to do when channel is stopped by sequencer. */
-
-       virtual void stopBySeq() = 0;
-
-       /* quantize
-        * start channel according to quantizer. Index = array index of
-        * mixer::channels, used by recorder. LocalFrame = frame within buffer.
-        * GloalFrame = actual frame from mixer. */
-
-       virtual void quantize(int index, int localFrame, int globalFrame) = 0;
-
-       /* onZero
-        * action to do when frame goes to zero, i.e. sequencer restart. */
-
-       virtual void onZero(int frame) = 0;
-
-       /* onBar
-        * action to do when a bar has passed. */
-
-       virtual void onBar(int frame) = 0;
-
-       /* parseAction
-        * do something on a recorded action. Parameters:
-        * action *a   - action to parse
-        * localFrame  - frame number of the processed buffer
-        * globalFrame - actual frame in Mixer */
-
-       virtual void parseAction(recorder::action *a, int localFrame, int globalFrame) = 0;
-
-       /* rewind
-        * rewind channel when rewind button is pressed. */
-
-       virtual void rewind() = 0;
-
-       /* ------------------------------------------------------------------------ */
-
-       int     index;                // unique id
-       int     type;                 // midi or sample
-       int     status;               // status: see const.h
-       int     key;                  // keyboard button
-       float   volume;               // global volume
-       float   volume_i;             // internal volume
-       float   volume_d;             // delta volume (for envelope)
-       float   panLeft;
-       float   panRight;
-       bool    mute_i;               // internal mute
-       bool      mute_s;               // previous mute status after being solo'd
-       bool    mute;                 // global mute
-       bool    solo;
-  bool    hasActions;           // has something recorded
-       int       recStatus;            // status of recordings (waiting, ending, ...)
-       float  *vChan;                // virtual channel
-  class   gChannel *guiChannel; // pointer to a gChannel object, part of the GUI
-
-       // TODO - midi structs, please
-
-  bool     midiIn;              // enable midi input
-  uint32_t midiInKeyPress;
-  uint32_t midiInKeyRel;
-  uint32_t midiInKill;
-  uint32_t midiInVolume;
-  uint32_t midiInMute;
-  uint32_t midiInSolo;
-
-       /*  midiOutL*
-        * Enable MIDI lightning output, plus a set of midi lighting event to be sent
-        * to a device. Those events basically contains the MIDI channel, everything
-        * else gets stripped out. */
-
-       bool     midiOutL;
-  uint32_t midiOutLplaying;
-  uint32_t midiOutLmute;
-  uint32_t midiOutLsolo;
-
-#ifdef WITH_VST
-  gVector <class Plugin *> plugins;
-#endif
-
-
-       /* ------------------------------------------------------------------------ */
-
-       /* isPlaying
-        * tell wether the channel is playing or is stopped. */
-
-       bool isPlaying();
-
-       /* readPatchMidiIn
-        * read from patch all midi-related parameters such as keypress, mute
-        * and so on. */
-
-       void readPatchMidiIn(int i);
-       void readPatchMidiOut(int i);
-
-       /* sendMidiL*
-        * send MIDI lightning events to a physical device. */
-
-       void sendMidiLmute();
-       void sendMidiLsolo();
-       void sendMidiLplay();
-};
-
-
-#endif
diff --git a/src/conf.cpp b/src/conf.cpp
deleted file mode 100644 (file)
index fd6720e..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * conf
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdlib.h>
-#include "const.h"
-#include "conf.h"
-#include "utils.h"
-#include "log.h"
-
-
-int Conf::openFileForReading()
-{
-       std::string path = gGetHomePath() + "/" + CONF_FILENAME;
-       fp = fopen(path.c_str(), "r");
-       if (fp == NULL) {
-               gLog("[Conf::openFile] unable to open conf file for reading\n");
-               return 0;
-       }
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Conf::createConfigFolder(const char *path)
-{
-       if (gDirExists(path))
-               return 1;
-
-       gLog("[Conf] .giada folder not present. Updating...\n");
-
-       if (gMkdir(path)) {
-               gLog("[Conf] status: ok\n");
-               return 1;
-       }
-       else {
-               gLog("[Conf] status: error!\n");
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Conf::openFileForWriting()
-{
-       /* writing config file. In windows is in the same dir of the .exe,
-        * in Linux and OS X in home */
-
-#if defined(__linux__)
-
-       char giadaPath[PATH_MAX];
-       sprintf(giadaPath, "%s/.giada", getenv("HOME"));
-
-       if (!createConfigFolder(giadaPath))
-               return 0;
-
-       char path[PATH_MAX];
-       sprintf(path, "%s/%s", giadaPath, CONF_FILENAME);
-
-#elif defined(_WIN32)
-
-       const char *path = CONF_FILENAME;
-
-#elif defined(__APPLE__)
-
-       struct passwd *p = getpwuid(getuid());
-       const char *home = p->pw_dir;
-       char giadaPath[PATH_MAX];
-       snprintf(giadaPath, PATH_MAX, "%s/Library/Application Support/Giada", home);
-
-       if (!createConfigFolder(giadaPath))
-               return 0;
-
-       char path[PATH_MAX];
-       sprintf(path, "%s/%s", giadaPath, CONF_FILENAME);
-
-#endif
-
-       fp = fopen(path, "w");
-       if (fp == NULL)
-               return 0;
-       return 1;
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Conf::setDefault()
-{
-       logMode = LOG_MODE_MUTE;
-
-       soundSystem    = DEFAULT_SOUNDSYS;
-       soundDeviceOut = DEFAULT_SOUNDDEV_OUT;
-       soundDeviceIn  = DEFAULT_SOUNDDEV_IN;
-       samplerate     = DEFAULT_SAMPLERATE;
-       buffersize     = DEFAULT_BUFSIZE;
-       delayComp      = DEFAULT_DELAYCOMP;
-       limitOutput    = false;
-       rsmpQuality    = 0;
-
-       midiPortIn     = DEFAULT_MIDI_PORT_IN;
-       noNoteOff      = false;
-       midiMapPath[0] = '\0';
-       midiPortOut    = DEFAULT_MIDI_PORT_OUT;
-       midiSync       = MIDI_SYNC_NONE;
-       midiTCfps      = 25.0f;
-
-       midiInRewind     = 0x0;
-       midiInStartStop  = 0x0;
-       midiInActionRec  = 0x0;
-       midiInInputRec   = 0x0;
-       midiInVolumeIn   = 0x0;
-       midiInVolumeOut  = 0x0;
-       midiInBeatDouble = 0x0;
-       midiInBeatHalf   = 0x0;
-       midiInMetronome  = 0x0;
-
-       pluginPath[0]  = '\0';
-       patchPath [0]  = '\0';
-       samplePath[0]  = '\0';
-
-       recsStopOnChanHalt = false;
-       chansStopOnSeqHalt = false;
-       treatRecsAsLoops   = false;
-
-       resizeRecordings = true;
-
-       actionEditorZoom    = 100;
-       actionEditorGridOn  = false;
-       actionEditorGridVal = 1;
-
-       mainWindowX = 0;
-       mainWindowY = 0;
-       mainWindowW = GUI_WIDTH;
-       mainWindowH = GUI_HEIGHT;
-
-       pianoRollY = -1;
-       pianoRollH = 422;
-}
-
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Conf::read()
-{
-       setDefault();
-
-       if (!openFileForReading()) {
-               gLog("[Conf] unreadable .conf file, using default parameters\n");
-               return 0;
-       }
-
-       if (getValue("header") != "GIADACFG") {
-               gLog("[Conf] corrupted .conf file, using default parameters\n");
-               return -1;
-       }
-
-       logMode = atoi(getValue("logMode").c_str());
-
-       soundSystem = atoi(getValue("soundSystem").c_str());
-       if (!soundSystem & (SYS_API_ANY)) soundSystem = DEFAULT_SOUNDSYS;
-
-       soundDeviceOut = atoi(getValue("soundDeviceOut").c_str());
-       if (soundDeviceOut < 0) soundDeviceOut = DEFAULT_SOUNDDEV_OUT;
-
-       soundDeviceIn = atoi(getValue("soundDeviceIn").c_str());
-       if (soundDeviceIn < -1) soundDeviceIn = DEFAULT_SOUNDDEV_IN;
-
-       channelsOut = atoi(getValue("channelsOut").c_str());
-       channelsIn  = atoi(getValue("channelsIn").c_str());
-       if (channelsOut < 0) channelsOut = 0;
-       if (channelsIn < 0)  channelsIn  = 0;
-
-       buffersize = atoi(getValue("buffersize").c_str());
-       if (buffersize < 8) buffersize = DEFAULT_BUFSIZE;
-
-       delayComp = atoi(getValue("delayComp").c_str());
-       if (delayComp < 0) delayComp = DEFAULT_DELAYCOMP;
-
-       midiSystem  = atoi(getValue("midiSystem").c_str());
-       if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_SYSTEM;
-
-       midiPortOut = atoi(getValue("midiPortOut").c_str());
-       if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_PORT_OUT;
-
-       midiPortIn = atoi(getValue("midiPortIn").c_str());
-       if (midiPortIn < -1) midiPortIn = DEFAULT_MIDI_PORT_IN;
-
-       noNoteOff = atoi(getValue("noNoteOff").c_str());
-
-       std::string tmpMidiMapPath = getValue("midiMapPath");
-       strncpy(midiMapPath, tmpMidiMapPath.c_str(), tmpMidiMapPath.size());
-       midiMapPath[tmpMidiMapPath.size()] = '\0';      // strncpy doesn't add '\0'
-
-       std::string tmplastFileMap = getValue("lastFileMap");
-       strncpy(lastFileMap, tmplastFileMap.c_str(), tmplastFileMap.size());
-       lastFileMap[tmplastFileMap.size()] = '\0';      // strncpy doesn't add '\0'
-
-       midiSync  = atoi(getValue("midiSync").c_str());
-       midiTCfps = atof(getValue("midiTCfps").c_str());
-
-       midiInRewind     = strtoul(getValue("midiInRewind").c_str(), NULL, 10);
-  midiInStartStop  = strtoul(getValue("midiInStartStop").c_str(), NULL, 10);
-  midiInActionRec  = strtoul(getValue("midiInActionRec").c_str(), NULL, 10);
-  midiInInputRec   = strtoul(getValue("midiInInputRec").c_str(), NULL, 10);
-  midiInMetronome  = strtoul(getValue("midiInMetronome").c_str(), NULL, 10);
-  midiInVolumeIn   = strtoul(getValue("midiInVolumeIn").c_str(), NULL, 10);
-  midiInVolumeOut  = strtoul(getValue("midiInVolumeOut").c_str(), NULL, 10);
-  midiInBeatDouble = strtoul(getValue("midiInBeatDouble").c_str(), NULL, 10);
-  midiInBeatHalf   = strtoul(getValue("midiInBeatHalf").c_str(), NULL, 10);
-
-       mainWindowX = atoi(getValue("mainWindowX").c_str());
-       mainWindowY = atoi(getValue("mainWindowY").c_str());
-       mainWindowW = atoi(getValue("mainWindowW").c_str());
-       mainWindowH = atoi(getValue("mainWindowH").c_str());
-
-       browserX = atoi(getValue("browserX").c_str());
-       browserY = atoi(getValue("browserY").c_str());
-       browserW = atoi(getValue("browserW").c_str());
-       browserH = atoi(getValue("browserH").c_str());
-       if (browserX < 0) browserX = 0;
-       if (browserY < 0) browserY = 0;
-       if (browserW < 396) browserW = 396;
-       if (browserH < 302) browserH = 302;
-
-       actionEditorX    = atoi(getValue("actionEditorX").c_str());
-       actionEditorY    = atoi(getValue("actionEditorY").c_str());
-       actionEditorW    = atoi(getValue("actionEditorW").c_str());
-       actionEditorH    = atoi(getValue("actionEditorH").c_str());
-       actionEditorZoom = atoi(getValue("actionEditorZoom").c_str());
-       actionEditorGridVal = atoi(getValue("actionEditorGridVal").c_str());
-       actionEditorGridOn  = atoi(getValue("actionEditorGridOn").c_str());
-       if (actionEditorX < 0)      actionEditorX = 0;
-       if (actionEditorY < 0)      actionEditorY = 0;
-       if (actionEditorW < 640)    actionEditorW = 640;
-       if (actionEditorH < 176)    actionEditorH = 176;
-       if (actionEditorZoom < 100) actionEditorZoom = 100;
-       if (actionEditorGridVal < 0) actionEditorGridVal = 0;
-       if (actionEditorGridOn < 0)  actionEditorGridOn = 0;
-
-       pianoRollY = atoi(getValue("pianoRollY").c_str());
-       pianoRollH = atoi(getValue("pianoRollH").c_str());
-       if (pianoRollH <= 0)
-               pianoRollH = 422;
-
-       sampleEditorX    = atoi(getValue("sampleEditorX").c_str());
-       sampleEditorY    = atoi(getValue("sampleEditorY").c_str());
-       sampleEditorW    = atoi(getValue("sampleEditorW").c_str());
-       sampleEditorH    = atoi(getValue("sampleEditorH").c_str());
-       sampleEditorGridVal = atoi(getValue("sampleEditorGridVal").c_str());
-       sampleEditorGridOn  = atoi(getValue("sampleEditorGridOn").c_str());
-  if (sampleEditorX < 0)   sampleEditorX = 0;
-       if (sampleEditorY < 0)   sampleEditorY = 0;
-       if (sampleEditorW < 500) sampleEditorW = 500;
-       if (sampleEditorH < 292) sampleEditorH = 292;
-       if (sampleEditorGridVal < 0) sampleEditorGridVal = 0;
-       if (sampleEditorGridOn < 0)  sampleEditorGridOn = 0;
-
-       configX = atoi(getValue("configX").c_str());
-       configY = atoi(getValue("configY").c_str());
-       if (configX < 0) configX = 0;
-       if (configY < 0) configY = 0;
-
-       pluginListX = atoi(getValue("pluginListX").c_str());
-       pluginListY = atoi(getValue("pluginListY").c_str());
-       if (pluginListX < 0) pluginListX = 0;
-       if (pluginListY < 0) pluginListY = 0;
-
-       bpmX = atoi(getValue("bpmX").c_str());
-       bpmY = atoi(getValue("bpmY").c_str());
-       if (bpmX < 0) bpmX = 0;
-       if (bpmY < 0) bpmY = 0;
-
-       beatsX = atoi(getValue("beatsX").c_str());
-       beatsY = atoi(getValue("beatsY").c_str());
-       if (beatsX < 0) beatsX = 0;
-       if (beatsY < 0) beatsY = 0;
-
-       aboutX = atoi(getValue("aboutX").c_str());
-       aboutY = atoi(getValue("aboutY").c_str());
-       if (aboutX < 0) aboutX = 0;
-       if (aboutY < 0) aboutY = 0;
-
-       samplerate = atoi(getValue("samplerate").c_str());
-       if (samplerate < 8000) samplerate = DEFAULT_SAMPLERATE;
-
-       limitOutput = atoi(getValue("limitOutput").c_str());
-       rsmpQuality = atoi(getValue("rsmpQuality").c_str());
-
-       std::string p = getValue("pluginPath");
-       strncpy(pluginPath, p.c_str(), p.size());
-       pluginPath[p.size()] = '\0';    // strncpy doesn't add '\0'
-
-       p = getValue("patchPath");
-       strncpy(patchPath, p.c_str(), p.size());
-       patchPath[p.size()] = '\0';     // strncpy doesn't add '\0'
-
-       p = getValue("samplePath");
-       strncpy(samplePath, p.c_str(), p.size());
-       samplePath[p.size()] = '\0';    // strncpy doesn't add '\0'
-
-       recsStopOnChanHalt = atoi(getValue("recsStopOnChanHalt").c_str());
-       chansStopOnSeqHalt = atoi(getValue("chansStopOnSeqHalt").c_str());
-       treatRecsAsLoops   = atoi(getValue("treatRecsAsLoops").c_str());
-
-       resizeRecordings = atoi(getValue("resizeRecordings").c_str());
-
-       close();
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Conf::write()
-{
-       if (!openFileForWriting())
-               return 0;
-
-       fprintf(fp, "# --- Giada configuration file --- \n");
-       fprintf(fp, "header=GIADACFG\n");
-       fprintf(fp, "version=%s\n", VERSIONE);
-
-       fprintf(fp, "logMode=%d\n",    logMode);
-
-       fprintf(fp, "soundSystem=%d\n",    soundSystem);
-       fprintf(fp, "soundDeviceOut=%d\n", soundDeviceOut);
-       fprintf(fp, "soundDeviceIn=%d\n",  soundDeviceIn);
-       fprintf(fp, "channelsOut=%d\n",    channelsOut);
-       fprintf(fp, "channelsIn=%d\n",     channelsIn);
-       fprintf(fp, "buffersize=%d\n",     buffersize);
-       fprintf(fp, "delayComp=%d\n",      delayComp);
-       fprintf(fp, "samplerate=%d\n",     samplerate);
-       fprintf(fp, "limitOutput=%d\n",    limitOutput);
-       fprintf(fp, "rsmpQuality=%d\n",    rsmpQuality);
-
-       fprintf(fp, "midiSystem=%d\n",  midiSystem);
-       fprintf(fp, "midiPortOut=%d\n", midiPortOut);
-       fprintf(fp, "midiPortIn=%d\n",  midiPortIn);
-       fprintf(fp, "noNoteOff=%d\n",   noNoteOff);
-       fprintf(fp, "midiMapPath=%s\n", midiMapPath);
-       fprintf(fp, "lastFileMap=%s\n", lastFileMap);
-       fprintf(fp, "midiSync=%d\n",    midiSync);
-       fprintf(fp, "midiTCfps=%f\n",   midiTCfps);
-
-       fprintf(fp, "midiInRewind=%u\n",     midiInRewind);
-       fprintf(fp, "midiInStartStop=%u\n",  midiInStartStop);
-       fprintf(fp, "midiInActionRec=%u\n",  midiInActionRec);
-       fprintf(fp, "midiInInputRec=%u\n",   midiInInputRec);
-       fprintf(fp, "midiInMetronome=%u\n",  midiInMetronome);
-       fprintf(fp, "midiInVolumeIn=%u\n",   midiInVolumeIn);
-       fprintf(fp, "midiInVolumeOut=%u\n",  midiInVolumeOut);
-       fprintf(fp, "midiInBeatDouble=%u\n", midiInBeatDouble);
-       fprintf(fp, "midiInBeatHalf=%u\n",   midiInBeatHalf);
-
-       fprintf(fp, "pluginPath=%s\n", pluginPath);
-       fprintf(fp, "patchPath=%s\n",  patchPath);
-       fprintf(fp, "samplePath=%s\n", samplePath);
-
-       fprintf(fp, "mainWindowX=%d\n", mainWindowX);
-       fprintf(fp, "mainWindowY=%d\n", mainWindowY);
-       fprintf(fp, "mainWindowW=%d\n", mainWindowW);
-       fprintf(fp, "mainWindowH=%d\n", mainWindowH);
-
-       fprintf(fp, "browserX=%d\n", browserX);
-       fprintf(fp, "browserY=%d\n", browserY);
-       fprintf(fp, "browserW=%d\n", browserW);
-       fprintf(fp, "browserH=%d\n", browserH);
-
-       fprintf(fp, "actionEditorX=%d\n",       actionEditorX);
-       fprintf(fp, "actionEditorY=%d\n",       actionEditorY);
-       fprintf(fp, "actionEditorW=%d\n",       actionEditorW);
-       fprintf(fp, "actionEditorH=%d\n",       actionEditorH);
-       fprintf(fp, "actionEditorZoom=%d\n",    actionEditorZoom);
-       fprintf(fp, "actionEditorGridOn=%d\n",  actionEditorGridOn);
-       fprintf(fp, "actionEditorGridVal=%d\n", actionEditorGridVal);
-
-       fprintf(fp, "pianoRollY=%d\n", pianoRollY);
-       fprintf(fp, "pianoRollH=%d\n", pianoRollH);
-
-       fprintf(fp, "sampleEditorX=%d\n", sampleEditorX);
-       fprintf(fp, "sampleEditorY=%d\n", sampleEditorY);
-       fprintf(fp, "sampleEditorW=%d\n", sampleEditorW);
-       fprintf(fp, "sampleEditorH=%d\n", sampleEditorH);
-       fprintf(fp, "sampleEditorGridOn=%d\n",  sampleEditorGridOn);
-       fprintf(fp, "sampleEditorGridVal=%d\n", sampleEditorGridVal);
-
-       fprintf(fp, "configX=%d\n", configX);
-       fprintf(fp, "configY=%d\n", configY);
-
-       fprintf(fp, "pluginListX=%d\n", pluginListX);
-       fprintf(fp, "pluginListY=%d\n", pluginListY);
-
-       fprintf(fp, "bpmX=%d\n", bpmX);
-       fprintf(fp, "bpmY=%d\n", bpmY);
-
-       fprintf(fp, "beatsX=%d\n", beatsX);
-       fprintf(fp, "beatsY=%d\n", beatsY);
-
-       fprintf(fp, "aboutX=%d\n", aboutX);
-       fprintf(fp, "aboutY=%d\n", aboutY);
-
-       fprintf(fp, "recsStopOnChanHalt=%d\n", recsStopOnChanHalt);
-       fprintf(fp, "chansStopOnSeqHalt=%d\n", chansStopOnSeqHalt);
-       fprintf(fp, "treatRecsAsLoops=%d\n",   treatRecsAsLoops);
-
-       fprintf(fp, "resizeRecordings=%d\n", resizeRecordings);
-
-       close();
-       return 1;
-}
-
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Conf::close()
-{
-       if (fp != NULL)
-               fclose(fp);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Conf::setPath(char *path, const char *p)
-{
-       path[0] = '\0';
-       strncpy(path, p, strlen(p));
-       path[strlen(p)] = '\0';
-}
diff --git a/src/conf.h b/src/conf.h
deleted file mode 100644 (file)
index 9120f2e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * conf
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef __CONF_H__
-#define __CONF_H__
-
-
-#include <limits.h>
-#include <stdint.h>
-#include "dataStorage.h"
-
-
-#if defined(__APPLE__)
-       #include <pwd.h>
-#endif
-
-
-class Conf : public DataStorage
-{
-private:
-
-       int openFileForReading();
-       int openFileForWriting();
-       int createConfigFolder(const char *path);
-
-public:
-
-       int logMode;
-
-       int  soundSystem;
-       int  soundDeviceOut;
-       int  soundDeviceIn;
-       int  channelsOut;
-       int  channelsIn;
-       int  samplerate;
-       int  buffersize;
-       int  delayComp;
-       bool limitOutput;
-       int  rsmpQuality;
-
-       int   midiSystem;
-       int   midiPortOut;
-       int   midiPortIn;
-       bool  noNoteOff;
-       char  midiMapPath[FILENAME_MAX];
-       char  lastFileMap[FILENAME_MAX];
-       int   midiSync;  // see const.h
-       float midiTCfps;
-
-       uint32_t midiInRewind;
-       uint32_t midiInStartStop;
-       uint32_t midiInActionRec;
-       uint32_t midiInInputRec;
-       uint32_t midiInMetronome;
-       uint32_t midiInVolumeIn;
-       uint32_t midiInVolumeOut;
-       uint32_t midiInBeatDouble;
-       uint32_t midiInBeatHalf;
-
-       bool recsStopOnChanHalt;
-       bool chansStopOnSeqHalt;
-       bool treatRecsAsLoops;
-
-       bool resizeRecordings;
-
-       char pluginPath[FILENAME_MAX];
-       char patchPath [FILENAME_MAX];
-       char samplePath[FILENAME_MAX];
-
-       int  mainWindowX, mainWindowY, mainWindowW, mainWindowH;
-       int  browserX, browserY, browserW, browserH;
-       int  actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom;
-       int  actionEditorGridVal;
-       int  actionEditorGridOn;
-       int  sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH;
-  int  sampleEditorGridVal;
-  int  sampleEditorGridOn;
-       int  pianoRollY, pianoRollH;
-       int  pluginListX, pluginListY;
-       int  configX, configY;
-       int  bpmX, bpmY;
-       int  beatsX, beatsY;
-       int  aboutX, aboutY;
-
-       int  read();
-       int  write();
-       void setDefault();
-
-       /* setPath
-        * updates one of the following values: plugin, patch or sample.
-        * Pass it a pointer to one of these (path) and the string to save (p). */
-
-       void setPath(char *path, const char *p);
-
-       void close();
-};
-
-#endif
diff --git a/src/const.h b/src/const.h
deleted file mode 100644 (file)
index 9ada42e..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * const.h
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-#ifndef CONST_H
-#define CONST_H
-
-
-/* -- version --------------------------------------------------------------- */
-#define VERSIONE                               "0.10.0"
-#define VERSIONE_STR           "Giada"
-#define VERSIONE_FLOAT 1.0f
-
-#define CONF_FILENAME          "giada.conf"
-
-
-
-/* -- GUI ------------------------------------------------------------------- */
-#ifdef _WIN32
-       #define GUI_SLEEP                       1000/24
-#else
-       #define GUI_SLEEP                       1000000/24 // == 1.000.000 / 24 == 1/24 sec == 24 Hz
-#endif
-#define GUI_WIDTH                              810
-#define GUI_HEIGHT                     510
-
-#define COLOR_BD_0     fl_rgb_color(78,  78,  78)                      // border off
-#define COLOR_BD_1     fl_rgb_color(188, 188, 188)    // border on
-#define COLOR_BG_0     fl_rgb_color(37,  37,  37)     // bg off
-#define COLOR_BG_1     fl_rgb_color(78,  78,  78)     // bg on (clicked)
-#define COLOR_BG_2     fl_rgb_color(177, 142, 142)    // bg active (play, for some widgets)
-#define COLOR_BG_3     fl_rgb_color(28,  32,  80)     // bg input rec
-#define COLOR_BG_4     fl_rgb_color(113, 31,  31)     // bg action rec
-#define COLOR_ALERT    fl_rgb_color(239, 75,  53)     // peak meter alert
-#define COLOR_TEXT_0   fl_rgb_color(200, 200, 200)
-#define COLOR_TEXT_1   fl_rgb_color(25,  25,  25)      // TODO - duplicate!
-#define COLOR_BG_MAIN  fl_rgb_color(25,  25,  25)                 // windows background
-#define COLOR_BG_DARK  fl_rgb_color(0,   0,   0)                  // inputs background
-
-
-
-/* -- MIN/MAX values -------------------------------------------------------- */
-#define MAX_BEATS                                 32
-#define MAX_BARS                                  32
-#define MAX_PATCHNAME_LEN       32
-#define DB_MIN_SCALE              60.0f
-#define MAX_VST_EVENTS     32
-
-
-
-/* -- kernel audio ---------------------------------------------------------- */
-#define SYS_API_JACK           0x01  // 0000 0001
-#define SYS_API_ALSA           0x02  // 0000 0010
-#define SYS_API_DS                     0x04  // 0000 0100
-#define SYS_API_ASIO           0x08  // 0000 1000
-#define SYS_API_CORE           0x10  // 0001 0000
-#define SYS_API_PULSE   0x20  // 0010 0000
-#define SYS_API_ANY     0x3F  // 0011 1111
-
-#define KERNEL_OK                                       0
-#define KERNEL_UNDERRUN          -1
-#define KERNEL_CRITICAL          -2
-
-
-
-/* -- kernel midi ----------------------------------------------------------- */
-#define MIDI_API_JACK          0x01  // 0000 0001
-#define MIDI_API_ALSA          0x02  // 0000 0010
-
-
-
-/* -- default system -------------------------------------------------------- */
-#if defined(__linux__)
-       #define DEFAULT_SOUNDSYS        SYS_API_ALSA
-#elif defined(_WIN32)
-       #define DEFAULT_SOUNDSYS        SYS_API_DS
-#elif defined(__APPLE__)
-       #define DEFAULT_SOUNDSYS        SYS_API_CORE
-#endif
-
-#define DEFAULT_SOUNDDEV_OUT  0       /// FIXME - please override with rtAudio::getDefaultDevice (or similar)
-#define DEFAULT_SOUNDDEV_IN   -1                       // no recording by default: input disabled
-#define DEFAULT_MIDI_SYSTEM   0
-#define DEFAULT_MIDI_PORT_IN  -1
-#define DEFAULT_MIDI_PORT_OUT -1
-#define DEFAULT_SAMPLERATE   44100
-#define DEFAULT_BUFSIZE                   1024
-#define DEFAULT_DELAYCOMP               0
-#define DEFAULT_VOL                               0.0f
-#define DEFAULT_BOOST                     0.0f
-#define gDEFAULT_PITCH                  1.0f   // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only).
-#define DEFAULT_OUT_VOL           1.0f
-#define DEFAULT_IN_VOL            0.0f
-#define DEFAULT_CHANMODE          SINGLE_BASIC
-#define DEFAULT_BPM                               120.0f
-#define DEFAULT_BEATS                     4
-#define DEFAULT_BARS                      1
-#define DEFAULT_QUANTIZE     0           // quantizer off
-#define DEFAULT_FADEOUT_STEP 0.01f  // micro-fadeout speed
-
-
-
-/* -- mixer statuses and modes ---------------------------------------------- */
-#define LOOP_BASIC                      0x01 // 0000 0001  chanMode
-#define LOOP_ONCE                               0x02 // 0000 0010  chanMode
-#define        SINGLE_BASIC             0x04 // 0000 0100  chanMode
-#define SINGLE_PRESS            0x08 // 0000 1000      chanMode
-#define SINGLE_RETRIG           0x10 // 0001 0000      chanMode
-#define LOOP_REPEAT                     0x20 // 0010 0000  chanMode
-#define SINGLE_ENDLESS   0x40 // 0100 0000  chanMode
-#define LOOP_ONCE_BAR    0x80 // 1000 0000  chanMode
-
-#define LOOP_ANY                                0xA3 // 1010 0011  chanMode - any loop mode
-#define SINGLE_ANY                0x5C // 0101 1100  chanMode - any single mode
-
-#define        STATUS_ENDING            0x01 // 0000 0001  chanStatus - ending            (loop mode only)
-#define        STATUS_WAIT                      0x02 // 0000 0010  chanStatus - waiting for start (loop mode only)
-#define        STATUS_PLAY                      0x04 // 0000 0100  chanStatus - playing
-#define STATUS_OFF                      0x08 // 0000 1000  chanStatus - off
-#define STATUS_EMPTY      0x10 // 0001 0000  chanStatus - not loaded (empty chan)
-#define STATUS_MISSING   0x20 // 0010 0000  chanStatus - not found
-#define STATUS_WRONG     0x40 // 0100 0000  chanStatus - something wrong (freq, bitrate, ...)
-
-#define REC_WAITING                     0x01 // 0000 0001
-#define REC_ENDING       0x02 // 0000 0010
-#define REC_READING      0x04 // 0000 0100
-#define REC_STOPPED      0x08 // 0000 1000
-
-
-
-/* -- actions --------------------------------------------------------------- */
-#define ACTION_KEYPRESS                0x01 // 0000 0001
-#define ACTION_KEYREL                  0x02 // 0000 0010
-#define ACTION_KILLCHAN                0x04 // 0000 0100
-#define ACTION_MUTEON                  0x08 // 0000 1000
-#define ACTION_MUTEOFF         0x10 // 0001 0000
-#define ACTION_VOLUME     0x20 // 0010 0000
-#define ACTION_MIDI       0x40 // 0100 0000
-
-#define ACTION_KEYS       0x03 // 0000 0011 any key
-#define ACTION_MUTES      0x24 // 0001 1000 any mute
-
-#define RANGE_CHAR        0x01 // range for MIDI (0-127)
-#define RANGE_FLOAT       0x02 // range for volumes and VST params (0.0-1.0)
-
-
-
-/* -- mixerHandler signals -------------------------------------------------- */
-#define SAMPLE_LOADED_OK      0x01
-#define SAMPLE_LEFT_EMPTY     0x02
-#define SAMPLE_NOT_VALID      0x04
-#define SAMPLE_MULTICHANNEL   0x08
-#define SAMPLE_WRONG_BIT      0x10
-#define SAMPLE_WRONG_ENDIAN   0x20
-#define SAMPLE_WRONG_FORMAT   0x40
-#define SAMPLE_READ_ERROR     0x80
-#define SAMPLE_PATH_TOO_LONG  0x100
-
-/** FIXME - add to SAMPLE_ series those for when exporting */
-
-
-
-/* -- log modes ------------------------------------------------------------- */
-#define LOG_MODE_STDOUT 0x01
-#define LOG_MODE_FILE   0x02
-#define LOG_MODE_MUTE   0x04
-
-
-
-/* -- browser types --------------------------------------------------------- */
-#define BROWSER_LOAD_PATCH   0x00
-#define BROWSER_LOAD_SAMPLE  0x01
-#define BROWSER_SAVE_PATCH   0x02
-#define BROWSER_SAVE_SAMPLE  0x04
-#define BROWSER_SAVE_PROJECT 0x08
-#define BROWSER_LOAD_PLUGIN  0x10
-
-
-
-/* -- channel types --------------------------------------------------------- */
-#define CHANNEL_SAMPLE 0x01
-#define CHANNEL_MIDI   0x02
-
-
-
-/* -- unique IDs of mainWin's subwindows ------------------------------------ */
-/* -- wid > 0 are reserved by gg_keyboard ----------------------------------- */
-#define WID_BEATS         -1
-#define WID_BPM           -2
-#define WID_ABOUT         -3
-#define WID_FILE_BROWSER  -4
-#define WID_CONFIG        -5
-#define WID_FX_LIST       -6
-#define WID_ACTION_EDITOR -7
-#define WID_SAMPLE_EDITOR -8
-#define WID_FX            -9
-#define WID_KEY_GRABBER   -10
-
-
-/* -- patch signals --------------------------------------------------------- */
-#define PATCH_UNREADABLE  0
-#define PATCH_INVALID    -1
-#define PATCH_OPEN_OK     1
-
-/** TODO - addo to PATCH_ serie the signals for saving/loading */
-
-
-
-/* -- MIDI signals -------------------------------------------------------------
- * all signals are set to channel 0 (where channels are considered).
- * It's up to the caller to bitmask them with the proper channel number. */
-
-/* channel voices messages - controller (0xB0) is a special subset of
- * this family: it drives knobs, volume, faders and such. */
-
-#define MIDI_CONTROLLER     0xB0 << 24
-#define MIDI_NOTE_ON        0x90 << 24
-#define MIDI_NOTE_OFF       0x80 << 24
-#define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16)
-#define MIDI_VOLUME        (MIDI_CONTROLLER) | (0x07 << 16)
-
-/* system common / real-time messages. Single bytes */
-
-#define MIDI_SYSEX          0xF0
-#define MIDI_MTC_QUARTER    0xF1
-#define MIDI_POSITION_PTR   0xF2
-#define MIDI_CLOCK          0xF8
-#define MIDI_START          0xFA
-#define MIDI_CONTINUE       0xFB
-#define MIDI_STOP           0xFC
-#define MIDI_EOX            0xF7  // end of sysex
-
-/* channels */
-
-#define MIDI_CHAN_0         0x00 << 24
-#define MIDI_CHAN_1         0x01 << 24
-#define MIDI_CHAN_2         0x02 << 24
-#define MIDI_CHAN_3         0x03 << 24
-#define MIDI_CHAN_4         0x04 << 24
-#define MIDI_CHAN_5         0x05 << 24
-#define MIDI_CHAN_6         0x06 << 24
-#define MIDI_CHAN_7         0x07 << 24
-#define MIDI_CHAN_8         0x08 << 24
-#define MIDI_CHAN_9         0x09 << 24
-#define MIDI_CHAN_10        0x0A << 24
-#define MIDI_CHAN_11        0x0B << 24
-#define MIDI_CHAN_12        0x0C << 24
-#define MIDI_CHAN_13        0x0D << 24
-#define MIDI_CHAN_14        0x0E << 24
-#define MIDI_CHAN_15        0x0F << 24
-
-const int MIDI_CHANS[16] = {
-       MIDI_CHAN_0,  MIDI_CHAN_1,      MIDI_CHAN_2,  MIDI_CHAN_3,
-       MIDI_CHAN_4,  MIDI_CHAN_5,      MIDI_CHAN_6,  MIDI_CHAN_7,
-       MIDI_CHAN_8,  MIDI_CHAN_9,      MIDI_CHAN_10, MIDI_CHAN_11,
-       MIDI_CHAN_12, MIDI_CHAN_13,     MIDI_CHAN_14, MIDI_CHAN_15
-};
-
-/* midi sync constants */
-
-#define MIDI_SYNC_NONE      0x00
-#define MIDI_SYNC_CLOCK_M   0x01
-#define MIDI_SYNC_CLOCK_S   0x02
-#define MIDI_SYNC_MTC_M     0x04
-#define MIDI_SYNC_MTC_S     0x08
-
-#endif
diff --git a/src/core/.dirstamp b/src/core/.dirstamp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/core/channel.cpp b/src/core/channel.cpp
new file mode 100644 (file)
index 0000000..85ee975
--- /dev/null
@@ -0,0 +1,234 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../utils/log.h"
+#include "../gui/elems/ge_channel.h"
+#include "channel.h"
+#include "pluginHost.h"
+#include "kernelMidi.h"
+#include "patch.h"
+#include "wave.h"
+#include "mixer.h"
+#include "mixerHandler.h"
+#include "conf.h"
+#include "waveFx.h"
+#include "midiMapConf.h"
+
+
+extern Patch       G_Patch;
+extern Mixer       G_Mixer;
+extern Conf        G_Conf;
+extern MidiMapConf G_MidiMap;
+#ifdef WITH_VST
+extern PluginHost  G_PluginHost;
+#endif
+
+
+Channel::Channel(int type, int status, int bufferSize)
+       : bufferSize(bufferSize),
+         type      (type),
+               status    (status),
+               key       (0),
+         volume    (DEFAULT_VOL),
+         volume_i  (1.0f),
+         volume_d  (0.0f),
+         panLeft   (1.0f),
+         panRight  (1.0f),
+         mute_i    (false),
+         mute_s    (false),
+         mute      (false),
+         solo      (false),
+         hasActions(false),
+         recStatus (REC_STOPPED),
+         vChan     (NULL),
+         guiChannel(NULL),
+         midiIn         (true),
+         midiInKeyPress (0x0),
+         midiInKeyRel   (0x0),
+         midiInKill     (0x0),
+         midiInVolume   (0x0),
+         midiInMute     (0x0),
+         midiInSolo     (0x0),
+         midiOutL       (false),
+         midiOutLplaying(0x0),
+         midiOutLmute   (0x0),
+         midiOutLsolo   (0x0)
+{
+       vChan = (float *) malloc(bufferSize * sizeof(float));
+       if (!vChan)
+               gLog("[Channel] unable to alloc memory for vChan\n");
+       memset(vChan, 0, bufferSize * sizeof(float));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+Channel::~Channel()
+{
+       status = STATUS_OFF;
+       if (vChan)
+               free(vChan);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset)
+{
+       gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
+               learn, chan, msg, offset);
+
+       uint32_t out;
+
+       /* isolate 'channel' from learnt message and offset it as requested by 'nn'
+        * in the midimap configuration file. */
+
+       out  = ((learn & 0x00FF0000) >> 16) << offset;
+
+       /* merge the previously prepared channel into final message, and finally
+        * send it. */
+
+       out |= msg | (chan << 24);
+       kernelMidi::send(out);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::readPatchMidiIn(int i)
+{
+       midiIn         = G_Patch.getMidiValue(i, "In");
+       midiInKeyPress = G_Patch.getMidiValue(i, "InKeyPress");
+       midiInKeyRel   = G_Patch.getMidiValue(i, "InKeyRel");
+  midiInKill     = G_Patch.getMidiValue(i, "InKill");
+  midiInVolume   = G_Patch.getMidiValue(i, "InVolume");
+  midiInMute     = G_Patch.getMidiValue(i, "InMute");
+  midiInSolo     = G_Patch.getMidiValue(i, "InSolo");
+}
+
+void Channel::readPatchMidiOut(int i)
+{
+       midiOutL        = G_Patch.getMidiValue(i, "OutL");
+       midiOutLplaying = G_Patch.getMidiValue(i, "OutLplaying");
+       midiOutLmute    = G_Patch.getMidiValue(i, "OutLmute");
+       midiOutLsolo    = G_Patch.getMidiValue(i, "OutLsolo");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool Channel::isPlaying()
+{
+       return status & (STATUS_PLAY | STATUS_ENDING);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::writePatch(FILE *fp, int i, bool isProject)
+{
+       fprintf(fp, "chanType%d=%d\n",     i, type);
+       fprintf(fp, "chanIndex%d=%d\n",    i, index);
+       fprintf(fp, "chanColumn%d=%d\n",   i, guiChannel->getColumnIndex());
+       fprintf(fp, "chanMute%d=%d\n",     i, mute);
+       fprintf(fp, "chanMute_s%d=%d\n",   i, mute_s);
+       fprintf(fp, "chanSolo%d=%d\n",     i, solo);
+       fprintf(fp, "chanvol%d=%f\n",      i, volume);
+       fprintf(fp, "chanPanLeft%d=%f\n",  i, panLeft);
+       fprintf(fp, "chanPanRight%d=%f\n", i, panRight);
+
+       fprintf(fp, "chanMidiIn%d=%u\n",         i, midiIn);
+       fprintf(fp, "chanMidiInKeyPress%d=%u\n", i, midiInKeyPress);
+       fprintf(fp, "chanMidiInKeyRel%d=%u\n",   i, midiInKeyRel);
+       fprintf(fp, "chanMidiInKill%d=%u\n",     i, midiInKill);
+       fprintf(fp, "chanMidiInVolume%d=%u\n",   i, midiInVolume);
+       fprintf(fp, "chanMidiInMute%d=%u\n",     i, midiInMute);
+       fprintf(fp, "chanMidiInSolo%d=%u\n",     i, midiInSolo);
+
+       fprintf(fp, "chanMidiOutL%d=%u\n",        i, midiOutL);
+       fprintf(fp, "chanMidiOutLplaying%d=%u\n", i, midiOutLplaying);
+       fprintf(fp, "chanMidiOutLmute%d=%u\n",    i, midiOutLmute);
+       fprintf(fp, "chanMidiOutLsolo%d=%u\n",    i, midiOutLsolo);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLmute()
+{
+       if (!midiOutL || midiOutLmute == 0x0)
+               return;
+       if (mute)
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOnChan, G_MidiMap.muteOnMsg, G_MidiMap.muteOnOffset);
+       else
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOffChan, G_MidiMap.muteOffMsg, G_MidiMap.muteOffOffset);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLsolo()
+{
+       if (!midiOutL || midiOutLsolo == 0x0)
+               return;
+       if (solo)
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOnChan, G_MidiMap.soloOnMsg, G_MidiMap.soloOnOffset);
+       else
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOffChan, G_MidiMap.soloOffMsg, G_MidiMap.soloOffOffset);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLplay()
+{
+       if (!midiOutL || midiOutLplaying == 0x0)
+               return;
+       switch (status) {
+               case STATUS_OFF:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppedChan, G_MidiMap.stoppedMsg, G_MidiMap.stoppedOffset);
+                       break;
+               case STATUS_PLAY:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.playingChan, G_MidiMap.playingMsg, G_MidiMap.playingOffset);
+                       break;
+               case STATUS_WAIT:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.waitingChan, G_MidiMap.waitingMsg, G_MidiMap.waitingOffset);
+                       break;
+               case STATUS_ENDING:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppingChan, G_MidiMap.stoppingMsg, G_MidiMap.stoppingOffset);
+       }
+}
diff --git a/src/core/channel.h b/src/core/channel.h
new file mode 100644 (file)
index 0000000..e346280
--- /dev/null
@@ -0,0 +1,221 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef CHANNEL_H
+#define CHANNEL_H
+
+
+#include "../utils/utils.h"
+#include "const.h"
+#include "recorder.h"
+
+
+#ifdef WITH_VST
+
+/* before including aeffetx(x).h we must define __cdecl, otherwise VST
+ * headers can't be compiled correctly. In windows __cdecl is already
+ * defined. */
+
+       #ifdef __GNUC__
+               #ifndef _WIN32
+                       #define __cdecl
+               #endif
+       #endif
+       #include "../deps/vst/aeffectx.h"
+
+#endif
+
+
+class Channel {
+
+protected:
+
+       /* bufferSize
+        * size of every buffer in this channel (vChan, pChan) */
+
+       int bufferSize;
+
+       /* sendMidiLMessage
+        * compose a MIDI message by merging bytes from MidiMap conf class, and send
+        * it to KernelMidi. */
+
+       void sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset);
+
+public:
+
+       Channel(int type, int status, int bufferSize);
+       virtual ~Channel();
+
+       /* writePatch
+        * store values in patch, writing to *fp. */
+
+       virtual void writePatch(FILE *fp, int i, bool isProject);
+
+       /* loadByPatch
+        * load a sample inside a patch. */
+
+       virtual int loadByPatch(const char *file, int i) = 0;
+
+       /* process
+        * merge vChannels into buffer, plus plugin processing (if any). */
+
+       virtual void process(float *buffer) = 0;
+
+       /* start
+        * action to do when channel starts. doQuantize = false (don't
+        * quantize) when Mixer is reading actions from Recorder::. */
+
+       virtual void start(int frame, bool doQuantize) = 0;
+
+       /* stop
+        * action to do when channel is stopped normally (via key or MIDI). */
+
+       virtual void stop() = 0;
+
+       /* kill
+        * action to do when channel stops abruptly. */
+
+       virtual void kill(int frame) = 0;
+
+       /* mute
+        * action to do when channel is muted. If internal == true, set
+        * internal mute without altering main mute. */
+
+       virtual void setMute  (bool internal) = 0;
+       virtual void unsetMute(bool internal) = 0;
+
+       /* empty
+        * free any associated resources (e.g. waveform for SAMPLE). */
+
+       virtual void empty() = 0;
+
+       /* stopBySeq
+        * action to do when channel is stopped by sequencer. */
+
+       virtual void stopBySeq() = 0;
+
+       /* quantize
+        * start channel according to quantizer. Index = array index of
+        * mixer::channels, used by recorder. LocalFrame = frame within buffer.
+        * GloalFrame = actual frame from mixer. */
+
+       virtual void quantize(int index, int localFrame, int globalFrame) = 0;
+
+       /* onZero
+        * action to do when frame goes to zero, i.e. sequencer restart. */
+
+       virtual void onZero(int frame) = 0;
+
+       /* onBar
+        * action to do when a bar has passed. */
+
+       virtual void onBar(int frame) = 0;
+
+       /* parseAction
+        * do something on a recorded action. Parameters:
+        * action *a   - action to parse
+        * localFrame  - frame number of the processed buffer
+        * globalFrame - actual frame in Mixer */
+
+       virtual void parseAction(recorder::action *a, int localFrame, int globalFrame) = 0;
+
+       /* rewind
+        * rewind channel when rewind button is pressed. */
+
+       virtual void rewind() = 0;
+
+       /* ------------------------------------------------------------------------ */
+
+       int     index;                // unique id
+       int     type;                 // midi or sample
+       int     status;               // status: see const.h
+       int     key;                  // keyboard button
+       float   volume;               // global volume
+       float   volume_i;             // internal volume
+       float   volume_d;             // delta volume (for envelope)
+       float   panLeft;
+       float   panRight;
+       bool    mute_i;               // internal mute
+       bool      mute_s;               // previous mute status after being solo'd
+       bool    mute;                 // global mute
+       bool    solo;
+  bool    hasActions;           // has something recorded
+       int       recStatus;            // status of recordings (waiting, ending, ...)
+       float  *vChan;                // virtual channel
+  class   gChannel *guiChannel; // pointer to a gChannel object, part of the GUI
+
+       // TODO - midi structs, please
+
+  bool     midiIn;              // enable midi input
+  uint32_t midiInKeyPress;
+  uint32_t midiInKeyRel;
+  uint32_t midiInKill;
+  uint32_t midiInVolume;
+  uint32_t midiInMute;
+  uint32_t midiInSolo;
+
+       /*  midiOutL*
+        * Enable MIDI lightning output, plus a set of midi lighting event to be sent
+        * to a device. Those events basically contains the MIDI channel, everything
+        * else gets stripped out. */
+
+       bool     midiOutL;
+  uint32_t midiOutLplaying;
+  uint32_t midiOutLmute;
+  uint32_t midiOutLsolo;
+
+#ifdef WITH_VST
+  gVector <class Plugin *> plugins;
+#endif
+
+
+       /* ------------------------------------------------------------------------ */
+
+       /* isPlaying
+        * tell wether the channel is playing or is stopped. */
+
+       bool isPlaying();
+
+       /* readPatchMidiIn
+        * read from patch all midi-related parameters such as keypress, mute
+        * and so on. */
+
+       void readPatchMidiIn(int i);
+       void readPatchMidiOut(int i);
+
+       /* sendMidiL*
+        * send MIDI lightning events to a physical device. */
+
+       void sendMidiLmute();
+       void sendMidiLsolo();
+       void sendMidiLplay();
+};
+
+
+#endif
diff --git a/src/core/conf.cpp b/src/core/conf.cpp
new file mode 100644 (file)
index 0000000..0dd258e
--- /dev/null
@@ -0,0 +1,467 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * conf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include "conf.h"
+#include "const.h"
+#include "../utils/utils.h"
+#include "../utils/log.h"
+
+
+int Conf::openFileForReading()
+{
+       std::string path = gGetHomePath() + "/" + CONF_FILENAME;
+       fp = fopen(path.c_str(), "r");
+       if (fp == NULL) {
+               gLog("[Conf::openFile] unable to open conf file for reading\n");
+               return 0;
+       }
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Conf::createConfigFolder(const char *path)
+{
+       if (gDirExists(path))
+               return 1;
+
+       gLog("[Conf] .giada folder not present. Updating...\n");
+
+       if (gMkdir(path)) {
+               gLog("[Conf] status: ok\n");
+               return 1;
+       }
+       else {
+               gLog("[Conf] status: error!\n");
+               return 0;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Conf::openFileForWriting()
+{
+       /* writing config file. In windows is in the same dir of the .exe,
+        * in Linux and OS X in home */
+
+#if defined(__linux__)
+
+       char giadaPath[PATH_MAX];
+       sprintf(giadaPath, "%s/.giada", getenv("HOME"));
+
+       if (!createConfigFolder(giadaPath))
+               return 0;
+
+       char path[PATH_MAX];
+       sprintf(path, "%s/%s", giadaPath, CONF_FILENAME);
+
+#elif defined(_WIN32)
+
+       const char *path = CONF_FILENAME;
+
+#elif defined(__APPLE__)
+
+       struct passwd *p = getpwuid(getuid());
+       const char *home = p->pw_dir;
+       char giadaPath[PATH_MAX];
+       snprintf(giadaPath, PATH_MAX, "%s/Library/Application Support/Giada", home);
+
+       if (!createConfigFolder(giadaPath))
+               return 0;
+
+       char path[PATH_MAX];
+       sprintf(path, "%s/%s", giadaPath, CONF_FILENAME);
+
+#endif
+
+       fp = fopen(path, "w");
+       if (fp == NULL)
+               return 0;
+       return 1;
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Conf::setDefault()
+{
+       logMode = LOG_MODE_MUTE;
+
+       soundSystem    = DEFAULT_SOUNDSYS;
+       soundDeviceOut = DEFAULT_SOUNDDEV_OUT;
+       soundDeviceIn  = DEFAULT_SOUNDDEV_IN;
+       samplerate     = DEFAULT_SAMPLERATE;
+       buffersize     = DEFAULT_BUFSIZE;
+       delayComp      = DEFAULT_DELAYCOMP;
+       limitOutput    = false;
+       rsmpQuality    = 0;
+
+       midiPortIn     = DEFAULT_MIDI_PORT_IN;
+       noNoteOff      = false;
+       midiMapPath[0] = '\0';
+       midiPortOut    = DEFAULT_MIDI_PORT_OUT;
+       midiSync       = MIDI_SYNC_NONE;
+       midiTCfps      = 25.0f;
+
+       midiInRewind     = 0x0;
+       midiInStartStop  = 0x0;
+       midiInActionRec  = 0x0;
+       midiInInputRec   = 0x0;
+       midiInVolumeIn   = 0x0;
+       midiInVolumeOut  = 0x0;
+       midiInBeatDouble = 0x0;
+       midiInBeatHalf   = 0x0;
+       midiInMetronome  = 0x0;
+
+       pluginPath[0]  = '\0';
+       patchPath [0]  = '\0';
+       samplePath[0]  = '\0';
+
+       recsStopOnChanHalt = false;
+       chansStopOnSeqHalt = false;
+       treatRecsAsLoops   = false;
+
+       resizeRecordings = true;
+
+       actionEditorZoom    = 100;
+       actionEditorGridOn  = false;
+       actionEditorGridVal = 1;
+
+       mainWindowX = 0;
+       mainWindowY = 0;
+       mainWindowW = GUI_WIDTH;
+       mainWindowH = GUI_HEIGHT;
+
+       pianoRollY = -1;
+       pianoRollH = 422;
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Conf::read()
+{
+       setDefault();
+
+       if (!openFileForReading()) {
+               gLog("[Conf] unreadable .conf file, using default parameters\n");
+               return 0;
+       }
+
+       if (getValue("header") != "GIADACFG") {
+               gLog("[Conf] corrupted .conf file, using default parameters\n");
+               return -1;
+       }
+
+       logMode = atoi(getValue("logMode").c_str());
+
+       soundSystem = atoi(getValue("soundSystem").c_str());
+       if (!(soundSystem & SYS_API_ANY)) soundSystem = DEFAULT_SOUNDSYS;
+
+       soundDeviceOut = atoi(getValue("soundDeviceOut").c_str());
+       if (soundDeviceOut < 0) soundDeviceOut = DEFAULT_SOUNDDEV_OUT;
+
+       soundDeviceIn = atoi(getValue("soundDeviceIn").c_str());
+       if (soundDeviceIn < -1) soundDeviceIn = DEFAULT_SOUNDDEV_IN;
+
+       channelsOut = atoi(getValue("channelsOut").c_str());
+       channelsIn  = atoi(getValue("channelsIn").c_str());
+       if (channelsOut < 0) channelsOut = 0;
+       if (channelsIn < 0)  channelsIn  = 0;
+
+       buffersize = atoi(getValue("buffersize").c_str());
+       if (buffersize < 8) buffersize = DEFAULT_BUFSIZE;
+
+       delayComp = atoi(getValue("delayComp").c_str());
+       if (delayComp < 0) delayComp = DEFAULT_DELAYCOMP;
+
+       midiSystem  = atoi(getValue("midiSystem").c_str());
+       if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_SYSTEM;
+
+       midiPortOut = atoi(getValue("midiPortOut").c_str());
+       if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_PORT_OUT;
+
+       midiPortIn = atoi(getValue("midiPortIn").c_str());
+       if (midiPortIn < -1) midiPortIn = DEFAULT_MIDI_PORT_IN;
+
+       noNoteOff = atoi(getValue("noNoteOff").c_str());
+
+       std::string tmpMidiMapPath = getValue("midiMapPath");
+       strncpy(midiMapPath, tmpMidiMapPath.c_str(), tmpMidiMapPath.size());
+       midiMapPath[tmpMidiMapPath.size()] = '\0';      // strncpy doesn't add '\0'
+
+       std::string tmplastFileMap = getValue("lastFileMap");
+       strncpy(lastFileMap, tmplastFileMap.c_str(), tmplastFileMap.size());
+       lastFileMap[tmplastFileMap.size()] = '\0';      // strncpy doesn't add '\0'
+
+       midiSync  = atoi(getValue("midiSync").c_str());
+       midiTCfps = atof(getValue("midiTCfps").c_str());
+
+       midiInRewind     = strtoul(getValue("midiInRewind").c_str(), NULL, 10);
+  midiInStartStop  = strtoul(getValue("midiInStartStop").c_str(), NULL, 10);
+  midiInActionRec  = strtoul(getValue("midiInActionRec").c_str(), NULL, 10);
+  midiInInputRec   = strtoul(getValue("midiInInputRec").c_str(), NULL, 10);
+  midiInMetronome  = strtoul(getValue("midiInMetronome").c_str(), NULL, 10);
+  midiInVolumeIn   = strtoul(getValue("midiInVolumeIn").c_str(), NULL, 10);
+  midiInVolumeOut  = strtoul(getValue("midiInVolumeOut").c_str(), NULL, 10);
+  midiInBeatDouble = strtoul(getValue("midiInBeatDouble").c_str(), NULL, 10);
+  midiInBeatHalf   = strtoul(getValue("midiInBeatHalf").c_str(), NULL, 10);
+
+       mainWindowX = atoi(getValue("mainWindowX").c_str());
+       mainWindowY = atoi(getValue("mainWindowY").c_str());
+       mainWindowW = atoi(getValue("mainWindowW").c_str());
+       mainWindowH = atoi(getValue("mainWindowH").c_str());
+
+       browserX = atoi(getValue("browserX").c_str());
+       browserY = atoi(getValue("browserY").c_str());
+       browserW = atoi(getValue("browserW").c_str());
+       browserH = atoi(getValue("browserH").c_str());
+       if (browserX < 0) browserX = 0;
+       if (browserY < 0) browserY = 0;
+       if (browserW < 396) browserW = 396;
+       if (browserH < 302) browserH = 302;
+
+       actionEditorX    = atoi(getValue("actionEditorX").c_str());
+       actionEditorY    = atoi(getValue("actionEditorY").c_str());
+       actionEditorW    = atoi(getValue("actionEditorW").c_str());
+       actionEditorH    = atoi(getValue("actionEditorH").c_str());
+       actionEditorZoom = atoi(getValue("actionEditorZoom").c_str());
+       actionEditorGridVal = atoi(getValue("actionEditorGridVal").c_str());
+       actionEditorGridOn  = atoi(getValue("actionEditorGridOn").c_str());
+       if (actionEditorX < 0)      actionEditorX = 0;
+       if (actionEditorY < 0)      actionEditorY = 0;
+       if (actionEditorW < 640)    actionEditorW = 640;
+       if (actionEditorH < 176)    actionEditorH = 176;
+       if (actionEditorZoom < 100) actionEditorZoom = 100;
+       if (actionEditorGridVal < 0) actionEditorGridVal = 0;
+       if (actionEditorGridOn < 0)  actionEditorGridOn = 0;
+
+       pianoRollY = atoi(getValue("pianoRollY").c_str());
+       pianoRollH = atoi(getValue("pianoRollH").c_str());
+       if (pianoRollH <= 0)
+               pianoRollH = 422;
+
+       sampleEditorX    = atoi(getValue("sampleEditorX").c_str());
+       sampleEditorY    = atoi(getValue("sampleEditorY").c_str());
+       sampleEditorW    = atoi(getValue("sampleEditorW").c_str());
+       sampleEditorH    = atoi(getValue("sampleEditorH").c_str());
+       sampleEditorGridVal = atoi(getValue("sampleEditorGridVal").c_str());
+       sampleEditorGridOn  = atoi(getValue("sampleEditorGridOn").c_str());
+  if (sampleEditorX < 0)   sampleEditorX = 0;
+       if (sampleEditorY < 0)   sampleEditorY = 0;
+       if (sampleEditorW < 500) sampleEditorW = 500;
+       if (sampleEditorH < 292) sampleEditorH = 292;
+       if (sampleEditorGridVal < 0) sampleEditorGridVal = 0;
+       if (sampleEditorGridOn < 0)  sampleEditorGridOn = 0;
+
+       configX = atoi(getValue("configX").c_str());
+       configY = atoi(getValue("configY").c_str());
+       if (configX < 0) configX = 0;
+       if (configY < 0) configY = 0;
+
+       pluginListX = atoi(getValue("pluginListX").c_str());
+       pluginListY = atoi(getValue("pluginListY").c_str());
+       if (pluginListX < 0) pluginListX = 0;
+       if (pluginListY < 0) pluginListY = 0;
+
+       bpmX = atoi(getValue("bpmX").c_str());
+       bpmY = atoi(getValue("bpmY").c_str());
+       if (bpmX < 0) bpmX = 0;
+       if (bpmY < 0) bpmY = 0;
+
+       beatsX = atoi(getValue("beatsX").c_str());
+       beatsY = atoi(getValue("beatsY").c_str());
+       if (beatsX < 0) beatsX = 0;
+       if (beatsY < 0) beatsY = 0;
+
+       aboutX = atoi(getValue("aboutX").c_str());
+       aboutY = atoi(getValue("aboutY").c_str());
+       if (aboutX < 0) aboutX = 0;
+       if (aboutY < 0) aboutY = 0;
+
+       samplerate = atoi(getValue("samplerate").c_str());
+       if (samplerate < 8000) samplerate = DEFAULT_SAMPLERATE;
+
+       limitOutput = atoi(getValue("limitOutput").c_str());
+       rsmpQuality = atoi(getValue("rsmpQuality").c_str());
+
+       std::string p = getValue("pluginPath");
+       strncpy(pluginPath, p.c_str(), p.size());
+       pluginPath[p.size()] = '\0';    // strncpy doesn't add '\0'
+
+       p = getValue("patchPath");
+       strncpy(patchPath, p.c_str(), p.size());
+       patchPath[p.size()] = '\0';     // strncpy doesn't add '\0'
+
+       p = getValue("samplePath");
+       strncpy(samplePath, p.c_str(), p.size());
+       samplePath[p.size()] = '\0';    // strncpy doesn't add '\0'
+
+       recsStopOnChanHalt = atoi(getValue("recsStopOnChanHalt").c_str());
+       chansStopOnSeqHalt = atoi(getValue("chansStopOnSeqHalt").c_str());
+       treatRecsAsLoops   = atoi(getValue("treatRecsAsLoops").c_str());
+
+       resizeRecordings = atoi(getValue("resizeRecordings").c_str());
+
+       close();
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Conf::write()
+{
+       if (!openFileForWriting())
+               return 0;
+
+       fprintf(fp, "# --- Giada configuration file --- \n");
+       fprintf(fp, "header=GIADACFG\n");
+       fprintf(fp, "version=%s\n", VERSIONE);
+
+       fprintf(fp, "logMode=%d\n",    logMode);
+
+       fprintf(fp, "soundSystem=%d\n",    soundSystem);
+       fprintf(fp, "soundDeviceOut=%d\n", soundDeviceOut);
+       fprintf(fp, "soundDeviceIn=%d\n",  soundDeviceIn);
+       fprintf(fp, "channelsOut=%d\n",    channelsOut);
+       fprintf(fp, "channelsIn=%d\n",     channelsIn);
+       fprintf(fp, "buffersize=%d\n",     buffersize);
+       fprintf(fp, "delayComp=%d\n",      delayComp);
+       fprintf(fp, "samplerate=%d\n",     samplerate);
+       fprintf(fp, "limitOutput=%d\n",    limitOutput);
+       fprintf(fp, "rsmpQuality=%d\n",    rsmpQuality);
+
+       fprintf(fp, "midiSystem=%d\n",  midiSystem);
+       fprintf(fp, "midiPortOut=%d\n", midiPortOut);
+       fprintf(fp, "midiPortIn=%d\n",  midiPortIn);
+       fprintf(fp, "noNoteOff=%d\n",   noNoteOff);
+       fprintf(fp, "midiMapPath=%s\n", midiMapPath);
+       fprintf(fp, "lastFileMap=%s\n", lastFileMap);
+       fprintf(fp, "midiSync=%d\n",    midiSync);
+       fprintf(fp, "midiTCfps=%f\n",   midiTCfps);
+
+       fprintf(fp, "midiInRewind=%u\n",     midiInRewind);
+       fprintf(fp, "midiInStartStop=%u\n",  midiInStartStop);
+       fprintf(fp, "midiInActionRec=%u\n",  midiInActionRec);
+       fprintf(fp, "midiInInputRec=%u\n",   midiInInputRec);
+       fprintf(fp, "midiInMetronome=%u\n",  midiInMetronome);
+       fprintf(fp, "midiInVolumeIn=%u\n",   midiInVolumeIn);
+       fprintf(fp, "midiInVolumeOut=%u\n",  midiInVolumeOut);
+       fprintf(fp, "midiInBeatDouble=%u\n", midiInBeatDouble);
+       fprintf(fp, "midiInBeatHalf=%u\n",   midiInBeatHalf);
+
+       fprintf(fp, "pluginPath=%s\n", pluginPath);
+       fprintf(fp, "patchPath=%s\n",  patchPath);
+       fprintf(fp, "samplePath=%s\n", samplePath);
+
+       fprintf(fp, "mainWindowX=%d\n", mainWindowX);
+       fprintf(fp, "mainWindowY=%d\n", mainWindowY);
+       fprintf(fp, "mainWindowW=%d\n", mainWindowW);
+       fprintf(fp, "mainWindowH=%d\n", mainWindowH);
+
+       fprintf(fp, "browserX=%d\n", browserX);
+       fprintf(fp, "browserY=%d\n", browserY);
+       fprintf(fp, "browserW=%d\n", browserW);
+       fprintf(fp, "browserH=%d\n", browserH);
+
+       fprintf(fp, "actionEditorX=%d\n",       actionEditorX);
+       fprintf(fp, "actionEditorY=%d\n",       actionEditorY);
+       fprintf(fp, "actionEditorW=%d\n",       actionEditorW);
+       fprintf(fp, "actionEditorH=%d\n",       actionEditorH);
+       fprintf(fp, "actionEditorZoom=%d\n",    actionEditorZoom);
+       fprintf(fp, "actionEditorGridOn=%d\n",  actionEditorGridOn);
+       fprintf(fp, "actionEditorGridVal=%d\n", actionEditorGridVal);
+
+       fprintf(fp, "pianoRollY=%d\n", pianoRollY);
+       fprintf(fp, "pianoRollH=%d\n", pianoRollH);
+
+       fprintf(fp, "sampleEditorX=%d\n", sampleEditorX);
+       fprintf(fp, "sampleEditorY=%d\n", sampleEditorY);
+       fprintf(fp, "sampleEditorW=%d\n", sampleEditorW);
+       fprintf(fp, "sampleEditorH=%d\n", sampleEditorH);
+       fprintf(fp, "sampleEditorGridOn=%d\n",  sampleEditorGridOn);
+       fprintf(fp, "sampleEditorGridVal=%d\n", sampleEditorGridVal);
+
+       fprintf(fp, "configX=%d\n", configX);
+       fprintf(fp, "configY=%d\n", configY);
+
+       fprintf(fp, "pluginListX=%d\n", pluginListX);
+       fprintf(fp, "pluginListY=%d\n", pluginListY);
+
+       fprintf(fp, "bpmX=%d\n", bpmX);
+       fprintf(fp, "bpmY=%d\n", bpmY);
+
+       fprintf(fp, "beatsX=%d\n", beatsX);
+       fprintf(fp, "beatsY=%d\n", beatsY);
+
+       fprintf(fp, "aboutX=%d\n", aboutX);
+       fprintf(fp, "aboutY=%d\n", aboutY);
+
+       fprintf(fp, "recsStopOnChanHalt=%d\n", recsStopOnChanHalt);
+       fprintf(fp, "chansStopOnSeqHalt=%d\n", chansStopOnSeqHalt);
+       fprintf(fp, "treatRecsAsLoops=%d\n",   treatRecsAsLoops);
+
+       fprintf(fp, "resizeRecordings=%d\n", resizeRecordings);
+
+       close();
+       return 1;
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Conf::close()
+{
+       if (fp != NULL)
+               fclose(fp);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Conf::setPath(char *path, const char *p)
+{
+       path[0] = '\0';
+       strncpy(path, p, strlen(p));
+       path[strlen(p)] = '\0';
+}
diff --git a/src/core/conf.h b/src/core/conf.h
new file mode 100644 (file)
index 0000000..9120f2e
--- /dev/null
@@ -0,0 +1,124 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * conf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __CONF_H__
+#define __CONF_H__
+
+
+#include <limits.h>
+#include <stdint.h>
+#include "dataStorage.h"
+
+
+#if defined(__APPLE__)
+       #include <pwd.h>
+#endif
+
+
+class Conf : public DataStorage
+{
+private:
+
+       int openFileForReading();
+       int openFileForWriting();
+       int createConfigFolder(const char *path);
+
+public:
+
+       int logMode;
+
+       int  soundSystem;
+       int  soundDeviceOut;
+       int  soundDeviceIn;
+       int  channelsOut;
+       int  channelsIn;
+       int  samplerate;
+       int  buffersize;
+       int  delayComp;
+       bool limitOutput;
+       int  rsmpQuality;
+
+       int   midiSystem;
+       int   midiPortOut;
+       int   midiPortIn;
+       bool  noNoteOff;
+       char  midiMapPath[FILENAME_MAX];
+       char  lastFileMap[FILENAME_MAX];
+       int   midiSync;  // see const.h
+       float midiTCfps;
+
+       uint32_t midiInRewind;
+       uint32_t midiInStartStop;
+       uint32_t midiInActionRec;
+       uint32_t midiInInputRec;
+       uint32_t midiInMetronome;
+       uint32_t midiInVolumeIn;
+       uint32_t midiInVolumeOut;
+       uint32_t midiInBeatDouble;
+       uint32_t midiInBeatHalf;
+
+       bool recsStopOnChanHalt;
+       bool chansStopOnSeqHalt;
+       bool treatRecsAsLoops;
+
+       bool resizeRecordings;
+
+       char pluginPath[FILENAME_MAX];
+       char patchPath [FILENAME_MAX];
+       char samplePath[FILENAME_MAX];
+
+       int  mainWindowX, mainWindowY, mainWindowW, mainWindowH;
+       int  browserX, browserY, browserW, browserH;
+       int  actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom;
+       int  actionEditorGridVal;
+       int  actionEditorGridOn;
+       int  sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH;
+  int  sampleEditorGridVal;
+  int  sampleEditorGridOn;
+       int  pianoRollY, pianoRollH;
+       int  pluginListX, pluginListY;
+       int  configX, configY;
+       int  bpmX, bpmY;
+       int  beatsX, beatsY;
+       int  aboutX, aboutY;
+
+       int  read();
+       int  write();
+       void setDefault();
+
+       /* setPath
+        * updates one of the following values: plugin, patch or sample.
+        * Pass it a pointer to one of these (path) and the string to save (p). */
+
+       void setPath(char *path, const char *p);
+
+       void close();
+};
+
+#endif
diff --git a/src/core/const.h b/src/core/const.h
new file mode 100644 (file)
index 0000000..0b34668
--- /dev/null
@@ -0,0 +1,291 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * const.h
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef CONST_H
+#define CONST_H
+
+
+/* -- version --------------------------------------------------------------- */
+#define VERSIONE                               "0.10.1"
+#define VERSIONE_STR           "Giada"
+#define VERSIONE_FLOAT 1.01f
+
+#define CONF_FILENAME          "giada.conf"
+
+
+
+/* -- GUI ------------------------------------------------------------------- */
+#ifdef _WIN32
+       #define GUI_SLEEP                       1000/24
+#else
+       #define GUI_SLEEP                       1000000/24 // == 1.000.000 / 24 == 1/24 sec == 24 Hz
+#endif
+#define GUI_WIDTH                              810
+#define GUI_HEIGHT                     510
+
+#define COLOR_BD_0     fl_rgb_color(78,  78,  78)                      // border off
+#define COLOR_BD_1     fl_rgb_color(188, 188, 188)    // border on
+#define COLOR_BG_0     fl_rgb_color(37,  37,  37)     // bg off
+#define COLOR_BG_1     fl_rgb_color(78,  78,  78)     // bg on (clicked)
+#define COLOR_BG_2     fl_rgb_color(177, 142, 142)    // bg active (play, for some widgets)
+#define COLOR_BG_3     fl_rgb_color(28,  32,  80)     // bg input rec
+#define COLOR_BG_4     fl_rgb_color(113, 31,  31)     // bg action rec
+#define COLOR_ALERT    fl_rgb_color(239, 75,  53)     // peak meter alert
+#define COLOR_TEXT_0   fl_rgb_color(200, 200, 200)
+#define COLOR_TEXT_1   fl_rgb_color(25,  25,  25)      // TODO - duplicate!
+#define COLOR_BG_MAIN  fl_rgb_color(25,  25,  25)                 // windows background
+#define COLOR_BG_DARK  fl_rgb_color(0,   0,   0)                  // inputs background
+
+
+
+/* -- MIN/MAX values -------------------------------------------------------- */
+#define MAX_BEATS                                 32
+#define MAX_BARS                                  32
+#define MAX_PATCHNAME_LEN       32
+#define DB_MIN_SCALE              60.0f
+#define MAX_VST_EVENTS     32
+
+
+
+/* -- kernel audio ---------------------------------------------------------- */
+#define SYS_API_JACK           0x01  // 0000 0001
+#define SYS_API_ALSA           0x02  // 0000 0010
+#define SYS_API_DS                     0x04  // 0000 0100
+#define SYS_API_ASIO           0x08  // 0000 1000
+#define SYS_API_CORE           0x10  // 0001 0000
+#define SYS_API_PULSE   0x20  // 0010 0000
+#define SYS_API_ANY     0x3F  // 0011 1111
+
+#define KERNEL_OK                                       0
+#define KERNEL_UNDERRUN          -1
+#define KERNEL_CRITICAL          -2
+
+
+
+/* -- kernel midi ----------------------------------------------------------- */
+#define MIDI_API_JACK          0x01  // 0000 0001
+#define MIDI_API_ALSA          0x02  // 0000 0010
+
+
+
+/* -- default system -------------------------------------------------------- */
+#if defined(__linux__)
+       #define DEFAULT_SOUNDSYS        SYS_API_ALSA
+#elif defined(_WIN32)
+       #define DEFAULT_SOUNDSYS        SYS_API_DS
+#elif defined(__APPLE__)
+       #define DEFAULT_SOUNDSYS        SYS_API_CORE
+#endif
+
+#define DEFAULT_SOUNDDEV_OUT  0       /// FIXME - please override with rtAudio::getDefaultDevice (or similar)
+#define DEFAULT_SOUNDDEV_IN   -1                       // no recording by default: input disabled
+#define DEFAULT_MIDI_SYSTEM   0
+#define DEFAULT_MIDI_PORT_IN  -1
+#define DEFAULT_MIDI_PORT_OUT -1
+#define DEFAULT_SAMPLERATE   44100
+#define DEFAULT_BUFSIZE                   1024
+#define DEFAULT_DELAYCOMP               0
+#define DEFAULT_VOL                               0.0f
+#define DEFAULT_BOOST                     0.0f
+#define gDEFAULT_PITCH                  1.0f   // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only).
+#define DEFAULT_OUT_VOL           1.0f
+#define DEFAULT_IN_VOL            0.0f
+#define DEFAULT_CHANMODE          SINGLE_BASIC
+#define DEFAULT_BPM                               120.0f
+#define DEFAULT_BEATS                     4
+#define DEFAULT_BARS                      1
+#define DEFAULT_QUANTIZE     0           // quantizer off
+#define DEFAULT_FADEOUT_STEP 0.01f  // micro-fadeout speed
+
+
+
+/* -- mixer statuses and modes ---------------------------------------------- */
+#define LOOP_BASIC                      0x01 // 0000 0001  chanMode
+#define LOOP_ONCE                               0x02 // 0000 0010  chanMode
+#define        SINGLE_BASIC             0x04 // 0000 0100  chanMode
+#define SINGLE_PRESS            0x08 // 0000 1000      chanMode
+#define SINGLE_RETRIG           0x10 // 0001 0000      chanMode
+#define LOOP_REPEAT                     0x20 // 0010 0000  chanMode
+#define SINGLE_ENDLESS   0x40 // 0100 0000  chanMode
+#define LOOP_ONCE_BAR    0x80 // 1000 0000  chanMode
+
+#define LOOP_ANY                                0xA3 // 1010 0011  chanMode - any loop mode
+#define SINGLE_ANY                0x5C // 0101 1100  chanMode - any single mode
+
+#define        STATUS_ENDING            0x01 // 0000 0001  chanStatus - ending            (loop mode only)
+#define        STATUS_WAIT                      0x02 // 0000 0010  chanStatus - waiting for start (loop mode only)
+#define        STATUS_PLAY                      0x04 // 0000 0100  chanStatus - playing
+#define STATUS_OFF                      0x08 // 0000 1000  chanStatus - off
+#define STATUS_EMPTY      0x10 // 0001 0000  chanStatus - not loaded (empty chan)
+#define STATUS_MISSING   0x20 // 0010 0000  chanStatus - not found
+#define STATUS_WRONG     0x40 // 0100 0000  chanStatus - something wrong (freq, bitrate, ...)
+
+#define REC_WAITING                     0x01 // 0000 0001
+#define REC_ENDING       0x02 // 0000 0010
+#define REC_READING      0x04 // 0000 0100
+#define REC_STOPPED      0x08 // 0000 1000
+
+
+
+/* -- actions --------------------------------------------------------------- */
+#define ACTION_KEYPRESS                0x01 // 0000 0001
+#define ACTION_KEYREL                  0x02 // 0000 0010
+#define ACTION_KILLCHAN                0x04 // 0000 0100
+#define ACTION_MUTEON                  0x08 // 0000 1000
+#define ACTION_MUTEOFF         0x10 // 0001 0000
+#define ACTION_VOLUME     0x20 // 0010 0000
+#define ACTION_MIDI       0x40 // 0100 0000
+
+#define ACTION_KEYS       0x03 // 0000 0011 any key
+#define ACTION_MUTES      0x24 // 0001 1000 any mute
+
+#define RANGE_CHAR        0x01 // range for MIDI (0-127)
+#define RANGE_FLOAT       0x02 // range for volumes and VST params (0.0-1.0)
+
+
+
+/* -- mixerHandler signals -------------------------------------------------- */
+#define SAMPLE_LOADED_OK      0x01
+#define SAMPLE_LEFT_EMPTY     0x02
+#define SAMPLE_NOT_VALID      0x04
+#define SAMPLE_MULTICHANNEL   0x08
+#define SAMPLE_WRONG_BIT      0x10
+#define SAMPLE_WRONG_ENDIAN   0x20
+#define SAMPLE_WRONG_FORMAT   0x40
+#define SAMPLE_READ_ERROR     0x80
+#define SAMPLE_PATH_TOO_LONG  0x100
+
+/** FIXME - add to SAMPLE_ series those for when exporting */
+
+
+
+/* -- log modes ------------------------------------------------------------- */
+#define LOG_MODE_STDOUT 0x01
+#define LOG_MODE_FILE   0x02
+#define LOG_MODE_MUTE   0x04
+
+
+
+/* -- browser types --------------------------------------------------------- */
+#define BROWSER_LOAD_PATCH   0x00
+#define BROWSER_LOAD_SAMPLE  0x01
+#define BROWSER_SAVE_PATCH   0x02
+#define BROWSER_SAVE_SAMPLE  0x04
+#define BROWSER_SAVE_PROJECT 0x08
+#define BROWSER_LOAD_PLUGIN  0x10
+
+
+
+/* -- channel types --------------------------------------------------------- */
+#define CHANNEL_SAMPLE 0x01
+#define CHANNEL_MIDI   0x02
+
+
+
+/* -- unique IDs of mainWin's subwindows ------------------------------------ */
+/* -- wid > 0 are reserved by gg_keyboard ----------------------------------- */
+#define WID_BEATS         -1
+#define WID_BPM           -2
+#define WID_ABOUT         -3
+#define WID_FILE_BROWSER  -4
+#define WID_CONFIG        -5
+#define WID_FX_LIST       -6
+#define WID_ACTION_EDITOR -7
+#define WID_SAMPLE_EDITOR -8
+#define WID_FX            -9
+#define WID_KEY_GRABBER   -10
+
+
+/* -- patch signals --------------------------------------------------------- */
+#define PATCH_UNREADABLE  0
+#define PATCH_INVALID    -1
+#define PATCH_OPEN_OK     1
+
+/** TODO - addo to PATCH_ serie the signals for saving/loading */
+
+
+
+/* -- MIDI signals -------------------------------------------------------------
+ * all signals are set to channel 0 (where channels are considered).
+ * It's up to the caller to bitmask them with the proper channel number. */
+
+/* channel voices messages - controller (0xB0) is a special subset of
+ * this family: it drives knobs, volume, faders and such. */
+
+#define MIDI_CONTROLLER     0xB0 << 24
+#define MIDI_NOTE_ON        0x90 << 24
+#define MIDI_NOTE_OFF       0x80 << 24
+#define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16)
+#define MIDI_VOLUME        (MIDI_CONTROLLER) | (0x07 << 16)
+
+/* system common / real-time messages. Single bytes */
+
+#define MIDI_SYSEX          0xF0
+#define MIDI_MTC_QUARTER    0xF1
+#define MIDI_POSITION_PTR   0xF2
+#define MIDI_CLOCK          0xF8
+#define MIDI_START          0xFA
+#define MIDI_CONTINUE       0xFB
+#define MIDI_STOP           0xFC
+#define MIDI_EOX            0xF7  // end of sysex
+
+/* channels */
+
+#define MIDI_CHAN_0         0x00 << 24
+#define MIDI_CHAN_1         0x01 << 24
+#define MIDI_CHAN_2         0x02 << 24
+#define MIDI_CHAN_3         0x03 << 24
+#define MIDI_CHAN_4         0x04 << 24
+#define MIDI_CHAN_5         0x05 << 24
+#define MIDI_CHAN_6         0x06 << 24
+#define MIDI_CHAN_7         0x07 << 24
+#define MIDI_CHAN_8         0x08 << 24
+#define MIDI_CHAN_9         0x09 << 24
+#define MIDI_CHAN_10        0x0A << 24
+#define MIDI_CHAN_11        0x0B << 24
+#define MIDI_CHAN_12        0x0C << 24
+#define MIDI_CHAN_13        0x0D << 24
+#define MIDI_CHAN_14        0x0E << 24
+#define MIDI_CHAN_15        0x0F << 24
+
+const int MIDI_CHANS[16] = {
+       MIDI_CHAN_0,  MIDI_CHAN_1,      MIDI_CHAN_2,  MIDI_CHAN_3,
+       MIDI_CHAN_4,  MIDI_CHAN_5,      MIDI_CHAN_6,  MIDI_CHAN_7,
+       MIDI_CHAN_8,  MIDI_CHAN_9,      MIDI_CHAN_10, MIDI_CHAN_11,
+       MIDI_CHAN_12, MIDI_CHAN_13,     MIDI_CHAN_14, MIDI_CHAN_15
+};
+
+/* midi sync constants */
+
+#define MIDI_SYNC_NONE      0x00
+#define MIDI_SYNC_CLOCK_M   0x01
+#define MIDI_SYNC_CLOCK_S   0x02
+#define MIDI_SYNC_MTC_M     0x04
+#define MIDI_SYNC_MTC_S     0x08
+
+#endif
diff --git a/src/core/dataStorage.cpp b/src/core/dataStorage.cpp
new file mode 100644 (file)
index 0000000..0cea01f
--- /dev/null
@@ -0,0 +1,70 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * dataStorage
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <limits.h>
+#include "../utils/log.h"
+#include "dataStorage.h"
+#include "const.h"
+
+
+std::string DataStorage::getValue(const char *in) {
+
+       /* on each call reset the pointe to the beginning of the file. Not so
+        * good but necessary if you want to pick up random values from the
+        * file. */
+
+       fseek(fp, 0L, SEEK_SET);
+       std::string out = "";
+
+       while (!feof(fp)) {
+
+               char buffer[MAX_LINE_LEN];
+               if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) {
+                       gLog("[PATCH] get_value error (key=%s)\n", in);
+                       return "";
+               }
+
+               if (buffer[0] == '#')
+                       continue;
+
+               unsigned len = strlen(in);
+               if (strncmp(buffer, in, len) == 0) {
+
+                       for (unsigned i=len+1; i<MAX_LINE_LEN; i++) {
+                               if (buffer[i] == '\0' || buffer[i] == '\n' || buffer[i] == '\r')
+                                       break;
+                               out += buffer[i];
+                       }
+
+                       break; // string found
+               }
+       }
+       return out;
+}
diff --git a/src/core/dataStorage.h b/src/core/dataStorage.h
new file mode 100644 (file)
index 0000000..9d54ddf
--- /dev/null
@@ -0,0 +1,48 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * dataStorage
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef __DATA_STORAGE_H__
+#define __DATA_STORAGE_H__
+
+#include <stdio.h>
+#include <string>
+#include <string.h>
+
+#define MAX_LINE_LEN 1024
+
+
+class DataStorage {
+
+protected:
+
+       FILE *fp;
+       std::string getValue(const char *in);
+};
+
+#endif
diff --git a/src/core/graphics.cpp b/src/core/graphics.cpp
new file mode 100644 (file)
index 0000000..7bed054
--- /dev/null
@@ -0,0 +1,1692 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * graphics
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#include "graphics.h"
+
+const char *giada_logo_xpm[] = {
+"300 82 8 1",
+"      c #181917",
+".     c #333432",
+"+     c #484A47",
+"@     c #5F615E",
+"#     c #767875",
+"$     c #8D8F8C",
+"%     c #A5A7A4",
+"&     c #C5C7C4",
+"                                                                                                                                                          .#%%&$                                                                                                                                            ",
+"                                                                                                                                                      ..#%&&&&&#                                                                                                                                            ",
+"                                                                                                                                                 +@#$%&&&&&&&&&@                                                                                                                                            ",
+"                                                              ..                                                                                +&&&&&&&&&&&&&&.                                                                                                                                            ",
+"                                                            +$%%#+                                                                              +%&&&&&&&&&&&&&.                                                                                                                                            ",
+"                                                           #&&&&&%+                                                                             .+@@$&&&&&&&&&%.                                                                                                                                            ",
+"                                                          #&&&&&&&$                                                                                  +&&&&&&&&#                                                                                                                                             ",
+"                                                         .&&&&&&&&%.                                                                                  #&&&&&&&@                                                                                                                                             ",
+"                                                         @&&&&&&&&$                                                                                   +&&&&&&&+                                                                                                                                             ",
+"                                                         $&&&&&&&&#                                                                                   .&&&&&&&.                                                                                                                                             ",
+"                                                         #&&&&&&&&.                                                                                   +&&&&&&%.                                                                                                                                             ",
+"                                                         .&&&&&&&@                                                                                    @&&&&&&$.                                                                                                                                             ",
+"                                                          @&&&&&@                                                                                     $&&&&&&#                                                                                                                                              ",
+"                                                           .##@.                                                                                      %&&&&&&@                                                                                                                                              ",
+"                                                                                                                                                      &&&&&&&+                                                                                                                                              ",
+"                                                                                                                                                     .&&&&&&%.                                                                                                                                              ",
+"                                                                                                                                                     @&&&&&&$.                                                                                                                                              ",
+"                     .+@@###@+.        ......               ...                      ++@@###@@.       .......                      .+@@###@@+.       #&&&&&&#                       .+@@###@@+        .......                                                                                               ",
+"                  .@$%%&&&&&&&%$+     +%%%%%%.         .+@#$%%$.                  .@$%&&&&&&&&%$@.    $%%%%%%+                  .@#%%&&&&&&&&%$@     %&&&&&&@                    .@$%%&&&&&&&%$#.    @%%%%%%@                                                                                               ",
+"                 #%&&&&&&&&&&&&&&$.   #&&&&&&    +@#$$%%%&&&&&%.                .$%&&&&&&&&&&&&&&%@  .&&&&&&&+                 #%&&&&&&&&&&&&&&&$+   &&&&&&&@                   #%&&&&&&&&&&&&&&%#.  %&&&&&&@                                                                                               ",
+"               +%&&&&&&&&&&&&&&&&&%@ .&&&&&&%   .%&&&&&&&&&&&&$                #%&&&&&&&&&&&&&&&&&&$ +&&&&&&%.               @%&&&&&&&&&&&&&&&&&&&# .&&&&&&%+                 @%&&&&&&&&&&&&&&&&&&%. &&&&&&&+                                                                                               ",
+"              #&&&&&&&&&#+....@$&&&&@@&&&&&&$   .&&&&&&&&&&&&&#              +%&&&&&&&&%#+....+#%&&&$#&&&&&&$.             .$&&&&&&&&&$+.....@%&&&&$@&&&&&&%.               .$&&&&&&&&&#@.....#%&&&%+&&&&&&%.                                                                                               ",
+"             $&&&&&&&&@         .%&&&&&&&&&&@    .@$&&&&&&&&&&@             +%&&&&&&&%@         .#&&&&&&&&&&$             .%&&&&&&&&@          .$&&&&&&&&&&$               .%&&&&&&&&#.         @&&&&&&&&&&%.                                                                                               ",
+"            $&&&&&&&%.            @&&&&&&&&&+       .%&&&&&&&%+            @&&&&&&&&#             +%&&&&&&&&#            +%&&&&&&&$.             @&&&&&&&&&#              .%&&&&&&&$.            .%&&&&&&&&$                                                                                                ",
+"           %&&&&&&&#               @&&&&&&&&.        +%&&&&&&%.           @&&&&&&&&#               .%&&&&&&&@           +%&&&&&&&#                @&&&&&&&&@             +%&&&&&&&#                %&&&&&&&@                                                                                                ",
+"          $&&&&&&&$                 #&&&&&&%.         %&&&&&&%           +&&&&&&&&@                 +&&&&&&%+          .%&&&&&&&#                  @&&&&&&&+            .%&&&&&&&#                  &&&&&&&+                                                                                                ",
+"         @&&&&&&&$.                 #&&&&&&$          %&&&&&&$          .%&&&&&&&@                  @&&&&&&%.         .$&&&&&&&$                   +&&&&&&%+            $&&&&&&&$                  .&&&&&&&+                                                                                                ",
+"        +&&&&&&&%+                  %&&&&&&#          %&&&&&&#          $&&&&&&&$                   $&&&&&&%          @&&&&&&&%                    #&&&&&&%.           #&&&&&&&%.                  @&&&&&&%.                                                                                                ",
+"        %&&&&&&&#                   &&&&&&&+         .%&&&&&&@         @&&&&&&&$                    %&&&&&&$         +&&&&&&&&+                    $&&&&&&$           +&&&&&&&%.                   $&&&&&&$.                                                                                                ",
+"       @&&&&&&&%.                  .&&&&&&&.         +%&&&&&%.        .&&&&&&&&.                   .%&&&&&&#         $&&&&&&&#                     %&&&&&&#          .$&&&&&&&@                    %&&&&&&#                                                                                                 ",
+"      .%&&&&&&&@                   @&&&&&&&.         @&&&&&&%         @&&&&&&&#                    @&&&&&&&+        +&&&&&&&&.                    +&&&&&&&@          +&&&&&&&%                    .&&&&&&&@                                                                                                 ",
+"      @&&&&&&&%                    $&&&&&&%.         #&&&&&&%         &&&&&&&&.                    #&&&&&&%.        %&&&&&&&#                     @&&&&&&%+         .$&&&&&&&@                    +&&&&&&&+                                                                                                 ",
+"     .$&&&&&&&#                    %&&&&&&#          $&&&&&&#        #&&&&&&&#                     $&&&&&&%        +&&&&&&&&.                     $&&&&&&%.         +&&&&&&&%                     #&&&&&&%+                                                                                                 ",
+"     +%&&&&&&&+                   .&&&&&&&@         .%&&&&&&@        %&&&&&&&+                    .%&&&&&&$        $&&&&&&&$                      %&&&&&&%          #&&&&&&&#                     %&&&&&&%.                                                                                                 ",
+"     @&&&&&&&%                    +&&&&&&&+         +%&&&&&&+       .&&&&&&&%.                    +&&&&&&&#        &&&&&&&&+                     +%&&&&&&$         .%&&&&&&&.                     &&&&&&&$                                                                                                  ",
+"     $&&&&&&&@                    #&&&&&&&.         @&&&&&&&.       #&&&&&&&#                     #&&&&&&&@       +&&&&&&&%.                     @&&&&&&&#         .&&&&&&&%                     +&&&&&&&#                                                                                                  ",
+"    .%&&&&&&&.                    %&&&&&&%.         #&&&&&&%        %&&&&&&&+                     $&&&&&&&+       #&&&&&&&$.                     $&&&&&&&+         @&&&&&&&@                     #&&&&&&&@                                                                                                  ",
+"    +&&&&&&&&                     &&&&&&&$.         #&&&&&&$        &&&&&&&%.                    .%&&&&&&&        %&&&&&&&#                     .%&&&&&&%.         $&&&&&&&+                     $&&&&&&%+                                                                                                  ",
+"    +&&&&&&&$                    +&&&&&&&#         .$&&&&&&#       .&&&&&&&$.                    +&&&&&&&%        %&&&&&&&+                     +%&&&&&&%          %&&&&&&&.                    .%&&&&&&%.                                                                                                  ",
+"    @&&&&&&&@                    $&&&&&&&@         .%&&&&&&+       +&&&&&&&#                     #&&&&&&&$        &&&&&&&&+                     #&&&&&&&%          &&&&&&&%                     @&&&&&&&$                                                                                                   ",
+"    @&&&&&&&+                    &&&&&&&&+         +%&&&&&&.       @&&&&&&&@                    .%&&&&&&&@       .&&&&&&&%.                    .%&&&&&&&#          &&&&&&&#                     $&&&&&&&$                                                                                                   ",
+"    #&&&&&&&.                   @&&&&&&&%.         @&&&&&&&        @&&&&&&&@                    @&&&&&&&&+       .&&&&&&&%.                    @&&&&&&&&@         .&&&&&&&#                    +%&&&&&&&#                                                                                                   ",
+"    #&&&&&&&.                   %&&&&&&&$.         #&&&&&&%        #&&&&&&&+                   .$&&&&&&&&.       .&&&&&&&$.                   .$&&&&&&&&.         .&&&&&&&@                    $&&&&&&&&@                                                                                                   ",
+"    #&&&&&&&                   #&&&&&&&&$          $&&&&&&#        @&&&&&&&+                   @&&&&&&&&&        .&&&&&&&$.                   @&&&&&&&&&          .&&&&&&&+                   +%&&&&&&&%+                                                                                                   ",
+"    @&&&&&&&                  .%&&&&&&&&#         .%&&&&&&@        @&&&&&&%+                  .%&&&&&&&&%         &&&&&&&$.                  .%&&&&&&&&%           &&&&&&&+                   $&&&&&&&&%.                                                                                                   ",
+"    @&&&&&&&.                 $&&&&&&&&&@         +%&&&&&&.        +&&&&&&&@                  @&&&&&&&&&$         &&&&&&&%.                  #&&&&&&&&&$           &&&&&&&@                  +&&&&&&&&&%                                                                                                    ",
+"    +&&&&&&&+                @&&&&&&&&&%+         +&&&&&&&          &&&&&&&@                 +&&&&&&&&&&#         $&&&&&&%+                 @&&&&&&&&&&#           $&&&&&&#                 .%&&&&&&&&&%                                                                                                    ",
+"    .%&&&&&&@               +%&&$&&&&&&%.         +&&&&&&&          %&&&&&&#                .&&&&&&&&&&&@         @&&&&&&&+                +&&&$%&&&&&&@           @&&&&&&$                .$&&&&&&&&&&$                                                                                                    ",
+"     #&&&&&&$              .$&&##&&&&&&$          @&&&&&&&          @&&&&&&%.              .%&&%@%&&&&&&@         .&&&&&&&#               .&&&$+%&&&&&&.           .&&&&&&&.              .#&&%@%&&&&&&$                                                                                                    ",
+"     +&&&&&&&.            .%&&% $&&&&&&#          +&&&&&&&.        +.&&&&&&&@             .%&&%+.%&&&&&&$        @+$&&&&&&&+             +&&&% +&&&&&&&+        .+  $&&&&&&$             .$&&&@ %&&&&&&%        .#                                                                                          ",
+"      $&&&&&&$           +%&&&+ %&&&&&&@          +&&&&&&&@       #&$#&&&&&&%+           @&&&&@ .$&&&&&&&+      #&&@&&&&&&&$.          .#&&&%. +%&&&&&&#       .$&$ +&&&&&&&+           +%&&&#  $&&&&&&&#      +&&$                                                                                         ",
+"      +%&&&&&&#.       +#&&&%@ .%&&&&&&+          .%&&&&&&&+    .$&&%.%&&&&&&%+        +#&&&&@   #&&&&&&&%@..+@$&&&+@&&&&&&&%+       .@%&&&%+  .%&&&&&&&+     +%&&$. #&&&&&&%@        +#&&&&#   @&&&&&&&&@...+#&&&#                                                                                         ",
+"       @&&&&&&&$@+..++#%&&&%+  +&&&&&&%.           $&&&&&&&%#@@#%&&%. .%&&&&&&%@+...+@$&&&&%+    +%&&&&&&&&%$%&&&&+  $&&&&&&&&$#@+@@#%&&&&$.    #&&&&&&&&#@+@$&&&$.  .$&&&&&&&#+...++#%&&&&@    .%&&&&&&&&%$%&&&&#                                                                                          ",
+"        @&&&&&&&&%%%%&&&&&$.   @&&&&&&%            +%&&&&&&&&&&&&&$.   +%&&&&&&&&%$%%&&&&&$.      #&&&&&&&&&&&&&%+   .$&&&&&&&&&&&&&&&&&&#      .%&&&&&&&&&&&&&&#     .$&&&&&&&&%$%%&&&&&%+      @&&&&&&&&&&&&&%@                                                                                           ",
+"         @%&&&&&&&&&&&&&%@.    #&&&&&&$             #&&&&&&&&&&&%@.     .$&&&&&&&&&&&&&&%@.       .%&&&&&&&&&&&#.      @&&&&&&&&&&&&&&&$+        +&&&&&&&&&&&&%+       .#&&&&&&&&&&&&&&&#.        $&&&&&&&&&&&$+                                                                                            ",
+"          .#%&&&&&&&&&%+.      %&&&&&&#              +%&&&&&&&%#.         +$&&&&&&&&&&%@.          .$&&&&&&&&#+         .#&&&&&&&&&&%#.           .$&&&&&&&&%@.          +$&&&&&&&&&&%@.          .@&&&&&&&&$+.                                                                                             ",
+"            .+#$%%$#+..       .%&&&&&&+               .@#$%$#+.             .@#$%%$#@+               +@$%$#+.             .+#$%%$#@+.               +@$%$$@.               .+#$%%$#@+.              .@$%$#@.                                                                                                ",
+"                              +&&&&&&%.                                                                                                                                                                                                                                                                     ",
+"                              #&&&&&&%                                                                                                                                                                                                                                                                      ",
+"                             .%&&&&&&@                                                                                                                                                                                                                                                                      ",
+"                             @&&&&&&%.                                                                                                                                                                                                                                                                      ",
+"                             $&&&&&&$                                                                                                                                                                                                                                                                       ",
+"                            @&&&&&&&+                                                                                                                                                                                                                                                                       ",
+"  @#$#+                    .$&&&&&&$                                                                                                                                                                                                                                                                        ",
+" $&&&&&#                   #&&&&&&%                                                                                                                                                                                                                                                                         ",
+"#&&&&&&&@                 @&&&&&&&+                                                                                                                                                                                                                                                                         ",
+"%&&&&&&&%.               @&&&&&&%+                                                                                                                                                                                                                                                                          ",
+"%&&&&&&&&#              #&&&&&&%.                                                                                                                                                                                                                                                                           ",
+"@&&&&&&&&&@           .$&&&&&&#.                                                                                                                                                                                                                                                                            ",
+" $&&&&&&&&&$+       +$&&&&&&%+                                                                                                                                                                                                                                                                              ",
+"  +&&&&&&&&&&%#@@#$%&&&&&&&#.                      +.     .+    +@.     ++    .+   +++++          +.    .+     ++     +++++.    .++++.        +@.       .@+     .++++.    .+++++++       +.         +@.       .+@.    .++++.         ++.      ++.    .+.      .+@.    .+     +.  .+  .+.    .+  .+++++++    ",
+"   .$&&&&&&&&&&&&&&&&&&&%@                         $%.    %@  +&&%&%.  .$$    +&  .&&&&&&#       .%@    +&.    %&+    $&&&&&%.  @&&&&&%.    +&&%&%.   .%&%&&+   #&&&&&&@  +&&&&&&%.      &#       +&&%&%.    @&&%&%.  +&&&&&&@       $&%     +%&+   .$&@     @&&%&$.  $%    .%$  $%  +&%.   +%. +&&&&&&$.   ",
+"      +$%%&&&&&&&&&&%$@.                           +&#   #%  +&#   %%   $$    +&  .&+   @&@      .%@    +&.   +$&$    $$   .%%  @%   .%&.  .&$  .%$.  %%.  #&+  #&   .$&+ +&.            &#      +&#   $%.  @&#  .%%. +&.   $&+      $%&+    #%&+   .&%$    @&#  +%$  $%    .%#  $%  +&%$   +%. +&.         ",
+"         .++@###@@+.                                #&. .&+  $%.   .&@  $$    +&  .&+    %$      .%@    +&.   ##$%    $$    @&. @%     %$  $%.   @&. @&+    %$. #&    .%@ +&.            &#      %%    .&#  %%    .&@ +&.    &#      $#%$    $#&+   @%@%.   %%    @%+ $%    .%#  $%  +&+%+  +%. +&.         ",
+"                                                    .%$ $$  .&#     %%  $$    +&  .&+    %$      .%@    +&.  .%@+&+   $$    @&. @%     #&  &#     +. %%     #&. #&    .%@ +&.            &#     .&@     $$ +&+    .$$ +&.    %#      $#@&   +$@&+   $#.%@  +&@    .+. $%    .%#  $%  +& $$  +%. +&.         ",
+"                                                     @&#&.  .&@     $&  $$    +&  .&#+++#&+      .%%####$&.  +%. %$   $%.++@&$  @%     +&..&@        &$     @&+ #&++++$%. +&$###@        &#     +&+     #%.@&.     #% +&+ ..#&+      $#.&@  ##+&+  .&..$$  @&.        $&$###$&#  $%  +& +%@ +%. +&####+     ",
+"                                                      %&@   +&+     #&  $$    +&  .&%$$%%@       .%%####$&.  #$  #&   $&$$%&#.  @%     +&++&@        &#     +&+ #&$$%&%+  +&$$$$#        &#     @&.     #%.@&.     #%.+%%%%%%@       $# $% .$+.&+  @%  @%. @&.        $&$###$&#  $%  +&  #%.+%. +&$$$$@     ",
+"                                                      #&.   .&@     $%  $$    +&  .&#+.$%.       .%@    +&. .$%##$&+  $%.+@&@   @%     +&..&@        &$     @&. #&+++$$   +&+            &#     +&.     #% @&.     $$ +&#@@++        $# +&.+$.+&+  $%@#$&+ @&.        $%    .%#  $%  +&  .%@+%. +&.         ",
+"                                                      @&    .%#     &$  $$    +%  .&+  .%@       .%@    +&. +%$###&$  $$   $%   @%     $&  &$    .$+ $%     #%. #&   +&+  +&.            &#     .&@    .%$ +&@    .%# +&.            $# .%### +&+ .&####&# .&@    .$+ $%    .%#  $%  +&   @%@%. +&.         ",
+"                                                      @&     #%.   @&.  #%.   $%  .&+   $%       .%@    +&. @$.   #&  $$   +&+  @%    +&@  #&.   #&. +&+   .%@  #&   .%#  +&.            &#      $%    +&+  %%    @&+ +&.            $#  #&%+ +&+ @%    #%. %%    #%. $%    .%#  $%  +&   .$%%. +&.         ",
+"                                                      @&     .%%+.@&#   .%%++#&@  .&+   +&+      .%@    +&. $#    .&+ $$    %$  @&+++#&%.   $%+.#&#   #&@.+%%.  #&    @%. +&@+++++.      &$++++. .%%+.@%#   .%%..@&#  +&.            $#  +&$  +&+ %#    +&+ .%%+.#&#  $%    .%#  $%  +&    +&&. +&@++++.  %&",
+"                                                      @&      .$&&%@     +%&&&@   .&+    %$      .%@    +&..%+     %$ $$    @&. @&&&&%@     .$%&&#     @%&&$.   #&    .%@ +&&&&&&%+      &&&&&&$. .$&&%#     .$&&%@   +&.            $#  .%#  +&+.&.    .%#  .$&&&@   $%    .%#  $%  +&     $&. +&&&&&&%. &&"};
+
+
+const char *loopRepeat_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #323331",
+"@     c #4D4F4C",
+"#     c #646663",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BFC1BD",
+"..................",
+"..................",
+"..................",
+"...&%#......#%&...",
+"...&&&%+..+%&&&...",
+"...$%&&%..%&&%$...",
+".....$&&##&&$.....",
+"......%&%%&%......",
+"......$&&&&$......",
+"......$&&&&$......",
+"......%&%%&%......",
+".....$&&##&&$.....",
+"...$%&&%..%&&%$...",
+"...&&&%+..+%&&&...",
+"...&%#......#%&...",
+"..................",
+"..................",
+".................."};
+
+
+const char *loopBasic_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #313230",
+"@     c #4D4F4C",
+"#     c #666765",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BEC0BD",
+"..................",
+"..................",
+"..................",
+"......#%&&%#......",
+"....+%&&&&&&%+....",
+"....%&&&%%&&&%....",
+"...#&&%+..+%&&#...",
+"...%&&+....+&&%...",
+"...&&%......%&&...",
+"...&&%......%&&...",
+"...%&&+....+&&%...",
+"...#&&%+..+%&&#...",
+"....%&&&%%&&&%....",
+"....+%&&&&&&%+....",
+"......#%&&%#......",
+"..................",
+"..................",
+".................."};
+
+
+const char *loopOnce_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #323331",
+"@     c #4D4F4C",
+"#     c #646663",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BFC1BD",
+"..................",
+"..................",
+"..................",
+"......$%&&%#......",
+"....+&&&&&&&&+....",
+"...+&&&&$$&&&&+...",
+"...$&&$....$&&$...",
+"...%&&......%&%...",
+"..................",
+"..................",
+"...%&&+.....&&&...",
+"...#&&$....$&&#...",
+"....%&&&%$&&&%....",
+"....+%&&&&&&%+....",
+"......#%&&%#......",
+"..................",
+"..................",
+".................."};
+
+
+const char *loopOnceBar_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #393A38",
+"+     c #545553",
+"@     c #747673",
+"#     c #A3A5A2",
+"$     c #ADAFAC",
+"%     c #B5B7B4",
+"&     c #C7C9C6",
+"                  ",
+"                  ",
+"                  ",
+"      @$&%#@      ",
+"    .$&&&&&&$.    ",
+"    %&&#@@#&&$    ",
+"   @&&@    @&&@   ",
+"   %&# +%$+ #&$   ",
+"       %&&%       ",
+"       %&&%       ",
+"   $&# +%%+ #&$   ",
+"   @&&@    @&&@   ",
+"    $&&#@@#&&$    ",
+"    .$&&&&&&$.    ",
+"      @#&&#@      ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *oneshotBasic_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #313230",
+"@     c #4D4F4C",
+"#     c #666765",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BEC0BD",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"...$$$$$$$$$$$$...",
+"...&&&&&&&&&&&&...",
+"...&&&&&&&&&&&&...",
+"..................",
+"..................",
+".................."};
+
+
+const char *oneshotRetrig_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #313230",
+"@     c #4D4F4C",
+"#     c #666765",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BEC0BD",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"...$$$$$$$#@......",
+"...&&&&&&&&&&@....",
+"...&&&&&&&&&&&+...",
+"..........+$&&%...",
+"............%&&...",
+"............%&&...",
+"...........+&&%...",
+"...$$$$$$$%&&&#...",
+"...&&&&&&&&&&%....",
+"...&&&&&&&&%#.....",
+"..................",
+"..................",
+".................."};
+
+
+const char *oneshotPress_xpm[] = {
+"18 18 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #313230",
+"@     c #4D4F4C",
+"#     c #666765",
+"$     c #787A77",
+"%     c #919390",
+"&     c #BEC0BD",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"...+%&%+..........",
+"...%&&&%..........",
+"...&&&&&..........",
+"...$&&&$..........",
+"...+$&$+..........",
+"..................",
+"...$$$$$$$$$$$$...",
+"...&&&&&&&&&&&&...",
+"...&&&&&&&&&&&&...",
+"..................",
+"..................",
+".................."};
+
+
+const char *oneshotEndless_xpm[] = {
+"18 18 6 1",
+"      c #242523",
+".     c #464745",
+"+     c #6D6F6C",
+"@     c #888A87",
+"#     c #ADAFAC",
+"$     c #C6C8C5",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"        .++.      ",
+"       @$$$$#.    ",
+"      @$$$$$$$.   ",
+"     .$$#. +$$@   ",
+"     +$$.   @$#   ",
+"     +$$    @$$   ",
+"     .$$+   #$#   ",
+"   @@@$$$@@#$$+   ",
+"   $$$$$$$$$$@    ",
+"   $$$$$$$$#+     ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *updirOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #332F2E",
+"+     c #54494A",
+"@     c #6B5A5C",
+"#     c #866C6B",
+"$     c #967B7A",
+"%     c #987D7C",
+"&     c #B18E8F",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"        @@        ",
+"       #&&#       ",
+"     .#&&&&#.     ",
+"    .$&&&&&&$.    ",
+"    +@%&&&&%@+    ",
+"      #&&&&#      ",
+"      #&&&&#      ",
+"      #&&&&#      ",
+"      #&&&&#      ",
+"      #&&&&#      ",
+"       ....       ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *updirOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #555150",
+"+     c #706465",
+"@     c #7D6B6E",
+"#     c #877373",
+"$     c #957978",
+"%     c #9F8382",
+"&     c #B18E8F",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"        ##        ",
+"       #&&#       ",
+"     .$&&&&$.     ",
+"    .%&&&&&&%.    ",
+"    +@%&&&&%@+    ",
+"      $&&&&$      ",
+"      $&&&&$      ",
+"      $&&&&$      ",
+"      $&&&&$      ",
+"      $&&&&$      ",
+"       ....       ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *pause_xpm[] = {
+"23 23 8 1",
+"      c #4D4F4C",
+".     c #514E53",
+"+     c #5C4F61",
+"@     c #6F507E",
+"#     c #855098",
+"$     c #9551AE",
+"%     c #A652C5",
+"&     c #AE52D1",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"       #+              ",
+"       &%#.            ",
+"       &&&%@           ",
+"       &&&&&$+         ",
+"       &&&&&&&#.       ",
+"       &&&&&&&&%@      ",
+"       &&&&&&&&&&#     ",
+"       &&&&&&&&%@.     ",
+"       &&&&&&&#.       ",
+"       &&&&&$+         ",
+"       &&&%@           ",
+"       &&#.            ",
+"       $+              ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+
+const char *play_xpm[] = {
+"23 23 8 1",
+"      c #242523",
+".     c #393534",
+"+     c #574B4C",
+"@     c #6E5B5A",
+"#     c #7C6663",
+"$     c #8C7170",
+"%     c #A48384",
+"&     c #B18E8F",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"       $.              ",
+"       &&@             ",
+"       &&&%+           ",
+"       &&&&&$.         ",
+"       &&&&&&&@        ",
+"       &&&&&&&&%+      ",
+"       &&&&&&&&&&#     ",
+"       &&&&&&&&%+      ",
+"       &&&&&&&#.       ",
+"       &&&&&$.         ",
+"       &&&%+           ",
+"       &&@             ",
+"       $.              ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+
+const char *rewindOff_xpm[] = {
+"23 23 8 1",
+"      c #242523",
+".     c #393534",
+"+     c #574B4C",
+"@     c #6E5B5A",
+"#     c #7C6663",
+"$     c #8C7170",
+"%     c #A48384",
+"&     c #B18E8F",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                .$     ",
+"               @&&     ",
+"             +%&&&     ",
+"           .$&&&&&     ",
+"          @&&&&&&&     ",
+"        +%&&&&&&&&     ",
+"       #&&&&&&&&&&     ",
+"        +%&&&&&&&&     ",
+"         .#&&&&&&&     ",
+"           .$&&&&&     ",
+"             +%&&&     ",
+"               @&&     ",
+"                .$     ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+
+const char *rewindOn_xpm[] = {
+"23 23 8 1",
+"      c #4D4F4C",
+".     c #514E53",
+"+     c #5C4F61",
+"@     c #6F507E",
+"#     c #855098",
+"$     c #9551AE",
+"%     c #A652C5",
+"&     c #AE52D1",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                +#     ",
+"              .#%&     ",
+"             @%&&&     ",
+"           +$&&&&&     ",
+"         .#&&&&&&&     ",
+"        @%&&&&&&&&     ",
+"       #&&&&&&&&&&     ",
+"       .@%&&&&&&&&     ",
+"         .#&&&&&&&     ",
+"           +$&&&&&     ",
+"             @%&&&     ",
+"              .#&&     ",
+"                +$     ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+
+// 18x18
+/*
+const unsigned char giada_icon[] = {
+   0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
+   0x3e, 0xf0, 0x01, 0x1e, 0xe0, 0x01, 0x0e, 0xc3, 0x01, 0x8e, 0xff, 0x01,
+   0x8e, 0xc1, 0x01, 0x8e, 0xc1, 0x01, 0x8e, 0xc7, 0x01, 0x0e, 0xc7, 0x01,
+   0x1e, 0xc0, 0x01, 0x3e, 0xf0, 0x01, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
+   0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 };
+*/
+
+const char *giada_icon[] = {
+"65 65 11 1",
+"      c None",
+".     c #000000",
+"+     c #000100",
+"@     c #FFFFFF",
+"#     c #FDFFFC",
+"$     c #CBCDC9",
+"%     c #292B28",
+"&     c #626461",
+"*     c #484A47",
+"=     c #888A87",
+"-     c #A7A9A6",
+"....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++....",
+".@@@#####################$%+++++++++++++%&&*%+++++++&##%+++++....",
+".@@#####################&++++++++++++=$#######-*+++++&$+++++++...",
+".@@####################&++++++++++%-############$*+++++++++++++..",
+"+#####################*++++++++++&################-++++++++++++%+",
+"+####################*++++++++++=##################$+++++++++++*+",
+"+###################*++++++++++$####################$++++++++++=+",
+"+##################=++++++++++-######################-+++++++++-+",
+"+#################$++++++++++=#######################=+++++++++$+",
+"+#################%+++++++++*########################*+++++++++#+",
+"+################*++++++++++#########################%++++++++*#+",
+"+###############-++++++++++=########################$+++++++++&#+",
+"+###############%+++++++++%#########################-+++++++++-#+",
+"+##############-++++++++++-#########################&+++++++++$#+",
+"+##############%+++++++++%##########################*+++++++++##+",
+"+#############-++++++++++-##########################+++++++++%##+",
+"+#############%++++++++++##########################$+++++++++*##+",
+"+############$++++++++++&##########################=+++++++++=##+",
+"+############=++++++++++$##########################&+++++++++-##+",
+"+############*+++++++++%###########################%+++++++++$##+",
+"+############++++++++++=###########################++++++++++###+",
+"+###########$++++++++++$##########################-+++++++++*###+",
+"+###########=++++++++++###########################=+++++++++&###+",
+"+###########*+++++++++%###########################*+++++++++-###+",
+"+###########%+++++++++&###########################++++++++++$###+",
+"+###########%+++++++++-##########################=++++++++++####+",
+"+###########++++++++++$##########################%+++++++++%####+",
+"+###########++++++++++##########################$++++++++++&####+",
+"+##########$++++++++++##########################&++++++++++=####+",
+"+##########$+++++++++%#########################$+++++++++++-####+",
+"+##########$+++++++++%#########################&+++++++++++$####+",
+"+###########+++++++++*########################$++++++++++++#####+",
+"+###########+++++++++*########################*+++++++++++*#####+",
+"+###########%++++++++%#######################=++++++++++++&#####+",
+"+###########&+++++++++######################$+++++++++++++-#####+",
+"+###########=+++++++++$#####################%+++%+++++++++$#####+",
+"+###########$+++++++++$####################&+++%=+++++++++######+",
+"+############%++++++++&###################=++++$&++++++++%######+",
+"+############-+++++++++$#################&++++=#*++++++++&######+",
+"+#############+++++++++&################*++++*##+++++++++=######+",
+"+#############=+++++++++-#############$%++++%###+++++++++-######+",
+"+##############*+++++++++=##########$*+++++%###$+++++++++#######+",
+"+###############++++++++++&$######$&++++++&####=+++++++++#######+",
+"+###############$++++++++++++%&*%++++++++=#####&++++++++*#######+",
+"+################$%+++++++++++++++++++++-######%++++++++=#######+",
+"+##################&++++++++++++++++++=########+++++++++-#######+",
+"+###################$%+++++++++++++%=#########$+++++++++########+",
+"+#####################$=%++++++%*=-###########=++++++++%########+",
+"+##########################$$$################*++++++++&########+",
+"+#############################################+++++++++=########+",
+"+############################################$+++++++++$########+",
+"+############################################&++++++++%#########+",
+"+############################################+++++++++=#########+",
+"+###########################################=+++++++++##########+",
+"+###########################################%++++++++*##########+",
+"+##########################################=+++++++++-##########+",
+"+#########-==$############################$+++++++++&###########+",
+"+#######=++++++-##########################*+++++++++############+",
+"+######$++++++++$########################=+++++++++-############+",
+"+######=+++++++++$######################-+++++++++&#############+",
+"+######=+++++++++*#####################$+++++++++&##############.",
+".@#####=++++++++++-###################-+++++++++=##############@.",
+".@@####=++++++++++%##################=+++++++++=#############@@@.",
+".@@@###=+++++++++++*###############$*++++++++%$##############@@@.",
+"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....."};
+
+const char *recOff_xpm[] = {
+"23 23 8 1",
+"      c #242523",
+".     c #342F2E",
+"+     c #3F3B3A",
+"@     c #594F4F",
+"#     c #7A6663",
+"$     c #8C7170",
+"%     c #A68384",
+"&     c #B18E8F",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"         @$%%$@        ",
+"       .$&&&&&&$.      ",
+"       $&&&&&&&&$      ",
+"      @&&&#++#&&&@     ",
+"      $&&#    #&&$     ",
+"      %&&+    +&&%     ",
+"      %&&+    +&&%     ",
+"      $&&#    #&&$     ",
+"      @&&&#++#&&&@     ",
+"       $&&&&&&&&$      ",
+"       .$&&&&&&$.      ",
+"         @$%%$@        ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+const char *recOn_xpm[] = {
+"23 23 8 1",
+"      c #4D4F4C",
+".     c #5F4E50",
+"+     c #6E4F50",
+"@     c #8C5050",
+"#     c #AE5454",
+"$     c #BB5253",
+"%     c #C55352",
+"&     c #E85557",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"         @$&&$@        ",
+"       .%&&&&&&%.      ",
+"       %&&&&&&&&%      ",
+"      @&&&#++#&&&@     ",
+"      $&&#    #&&$     ",
+"      &&&+    +&&&     ",
+"      &&&+    +&&&     ",
+"      $&&#    #&&$     ",
+"      @&&&#++#&&&@     ",
+"       %&&&&&&&&%      ",
+"       .%&&&&&&%.      ",
+"         @$&&$@        ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+const char *inputRecOn_xpm[] = {
+"23 23 8 1",
+"      c #524D4C",
+".     c #4D4F4C",
+"+     c #5D4F50",
+"@     c #8C5050",
+"#     c #BB5253",
+"$     c #C45251",
+"%     c #DD5256",
+"&     c #EA5657",
+".......................",
+".......................",
+".......................",
+".......................",
+".......................",
+"........ @#%%#@ .......",
+".......+$&&&&&&$+......",
+"...... $&&&&&&&&$ .....",
+"......@&&&&&&&&&&@.....",
+"......#&&&&&&&&&&#.....",
+"......%&&&&&&&&&&%.....",
+"......%&&&&&&&&&&%.....",
+"......#&&&&&&&&&&#.....",
+"......@&&&&&&&&&&@.....",
+".......$&&&&&&&&$......",
+".......+$&&&&&&$+......",
+"........ @#%%#@ .......",
+".......................",
+".......................",
+".......................",
+".......................",
+".......................",
+"......................."};
+
+const char *inputRecOff_xpm[] = {
+"23 23 8 1",
+"      c #242523",
+".     c #252724",
+"+     c #332F2E",
+"@     c #594E4F",
+"#     c #896E6D",
+"$     c #8D7271",
+"%     c #A68384",
+"&     c #B18E8F",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"        .@#%%#@.       ",
+"       +$&&&&&&$+      ",
+"      .$&&&&&&&&$.     ",
+"      @&&&&&&&&&&@     ",
+"      #&&&&&&&&&&#     ",
+"      %&&&&&&&&&&%     ",
+"      %&&&&&&&&&&%     ",
+"      #&&&&&&&&&&#     ",
+"      @&&&&&&&&&&@     ",
+"       $&&&&&&&&$      ",
+"       +$&&&&&&$+      ",
+"        .@#%%#@.       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       ",
+"                       "};
+
+const char *muteOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #2E2F2D",
+"+     c #3B3C3A",
+"@     c #525451",
+"#     c #6F716E",
+"$     c #878986",
+"%     c #ADAFAC",
+"&     c #C6C8C5",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     ++.  .++     ",
+"    +&&$  $&&+    ",
+"    +&&%  %&&+    ",
+"    +&%&++&%&+    ",
+"    +&$&##&$&+    ",
+"    +&#%$$%#&+    ",
+"    +&#$%%$#&+    ",
+"    +&#@&&@#&+    ",
+"    +&#+&&+#&+    ",
+"    .#@ ## @#.    ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+const char *muteOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #585A57",
+"+     c #616260",
+"@     c #7A7C79",
+"#     c #888A87",
+"$     c #989A97",
+"%     c #B2B4B1",
+"&     c #C6C8C5",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     ..    ..     ",
+"    +&&$  $&&+    ",
+"    +&&%  %&&+    ",
+"    +&%&++&%&+    ",
+"    +&$&@@&$&+    ",
+"    +&#%$$%#&+    ",
+"    +&#$&&$#&+    ",
+"    +&#@&&@#&+    ",
+"    +&#.&&.#&+    ",
+"    .#+ ## +#.    ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *readActionOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #393B38",
+"+     c #555754",
+"@     c #6B6D6A",
+"#     c #7F807E",
+"$     c #9C9E9B",
+"%     c #B1B3B0",
+"&     c #C3C5C2",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     ....         ",
+"     %&&&&%+      ",
+"     %&@@@&&      ",
+"     %%   $&.     ",
+"     %&@@#&$      ",
+"     %&&&&@       ",
+"     %% +&$       ",
+"     %%  #&#      ",
+"     %%   %&+     ",
+"     @@   .#+     ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *readActionOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #696B68",
+"+     c #7A7C79",
+"@     c #888A87",
+"#     c #939592",
+"$     c #A7A9A6",
+"%     c #B7B9B6",
+"&     c #C4C6C3",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     %&&&&%.      ",
+"     %&++@&&      ",
+"     %%   $&      ",
+"     %&@@#&$      ",
+"     %&&&&@       ",
+"     %% +&$       ",
+"     %%  #&#      ",
+"     %%   %&.     ",
+"     +@   .@+     ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *metronomeOff_xpm[] = {
+"13 13 8 1",
+"      c #242523",
+".     c #2D2928",
+"+     c #34302F",
+"@     c #443D3C",
+"#     c #4F4445",
+"$     c #685659",
+"%     c #826A68",
+"&     c #A18282",
+"             ",
+"             ",
+"  .       .  ",
+" #%       %# ",
+" .&+     +&. ",
+"  %$     $%  ",
+"  @&     &@  ",
+"   &@   @&   ",
+"   $%   %$   ",
+"   +&. .&+   ",
+"    %# #%    ",
+"    .   .    ",
+"             "};
+
+
+const char *metronomeOn_xpm[] = {
+"13 13 8 1",
+"      c #4D4F4C",
+".     c #565150",
+"+     c #645C5C",
+"@     c #716465",
+"#     c #837070",
+"$     c #8F7775",
+"%     c #977C7B",
+"&     c #A68787",
+"             ",
+"             ",
+"  .       .  ",
+" @%       %@ ",
+" .&.     .&. ",
+"  $#     #$  ",
+"  +&     &+  ",
+"   &+   +&   ",
+"   #$   $#   ",
+"   .&. .&.   ",
+"    %@ @%    ",
+"    .   .    ",
+"             "};
+
+
+const char *zoomInOff_xpm[] = {
+"18 18 8 1",
+"      c None",
+".     c #252525",
+"+     c #262626",
+"@     c #535353",
+"#     c #ACACAC",
+"$     c #AEAEAE",
+"%     c #B1B1B1",
+"&     c #C4C4C4",
+"++++++++++++++++++",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+.......@@.......+",
+"+.......#$.......+",
+"+.......#$.......+",
+"+....@%%&&%%@....+",
+"+....@%%&&%%@....+",
+"+.......#$.......+",
+"+.......#$.......+",
+"+.......@@.......+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"++++++++++++++++++"};
+
+
+const char *zoomInOn_xpm[] = {
+"18 18 8 1",
+"      c None",
+".     c #4E4E4E",
+"+     c #707070",
+"@     c #717171",
+"#     c #B3B3B3",
+"$     c #B5B5B5",
+"%     c #B7B7B7",
+"&     c #C5C5C5",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"........++........",
+"........#$........",
+"........#$........",
+".....@%%&&%%@.....",
+".....@%%&&%%@.....",
+"........#$........",
+"........#$........",
+"........++........",
+"..................",
+"..................",
+"..................",
+"..................",
+".................."};
+
+
+const char *zoomOutOff_xpm[] = {
+"18 18 5 1",
+"      c None",
+".     c #252525",
+"+     c #262626",
+"@     c #9C9C9C",
+"#     c #BBBBBB",
+"++++++++++++++++++",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+......@##@......+",
+"+......@##@......+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"+................+",
+"++++++++++++++++++"};
+
+
+const char *zoomOutOn_xpm[] = {
+"18 18 4 1",
+"      c None",
+".     c #4E4E4E",
+"+     c #A7A7A7",
+"@     c #BEBEBE",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+".......+@@+.......",
+".......+@@+.......",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+".................."};
+
+
+
+const char *scrollRightOff_xpm[] = {
+"12 12 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #2E2F2D",
+"@     c #4D4F4C",
+"#     c #5D5F5C",
+"$     c #828481",
+"%     c #9B9D9A",
+"&     c #BCBEBB",
+"............",
+"............",
+"...+........",
+"...&$@......",
+"...$&&%@....",
+"....+#%&%...",
+"....+#%&%...",
+"...$&&%#....",
+"...&$@......",
+"...+........",
+"............",
+"............"};
+
+
+const char *scrollLeftOff_xpm[] = {
+"12 12 8 1",
+"      c #181917",
+".     c #242523",
+"+     c #2E2F2D",
+"@     c #4D4F4C",
+"#     c #5D5F5C",
+"$     c #828481",
+"%     c #9B9D9A",
+"&     c #BCBEBB",
+"............",
+"............",
+"........+...",
+"......@$&...",
+"....@%&&$...",
+"...%&%#+....",
+"...%&%#+....",
+"....#%&&$...",
+"......@$&...",
+"........+...",
+"............",
+"............"};
+
+
+const char *scrollLeftOn_xpm[] = {
+"12 12 8 1",
+"      c #4D4F4C",
+".     c #6B6D6A",
+"+     c #7B7D7A",
+"@     c #969895",
+"#     c #A6A8A5",
+"$     c #B4B6B3",
+"%     c #C0C2BF",
+"&     c #FEFFFC",
+"            ",
+"            ",
+"            ",
+"      .@$   ",
+"    +#%%@   ",
+"   $%#+     ",
+"   %%#+     ",
+"    +$%%@   ",
+"      .#$   ",
+"            ",
+"            ",
+"            "};
+
+
+const char *scrollRightOn_xpm[] = {
+"12 12 8 1",
+"      c #4D4F4C",
+".     c #6B6D6A",
+"+     c #7B7D7A",
+"@     c #969895",
+"#     c #A6A8A5",
+"$     c #B4B6B3",
+"%     c #C0C2BF",
+"&     c #FEFFFC",
+"            ",
+"            ",
+"            ",
+"   %@.      ",
+"   @%%#.    ",
+"     +#%#   ",
+"     +#%#   ",
+"   @%%#+    ",
+"   %@.      ",
+"            ",
+"            ",
+"            "};
+
+
+const char *soloOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #616360",
+"+     c #737572",
+"@     c #838582",
+"#     c #929491",
+"$     c #A5A7A4",
+"%     c #B1B3B0",
+"&     c #C6C8C5",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"       .@+.       ",
+"      #&&&&#      ",
+"     .&$  %&.     ",
+"      &%+ ..      ",
+"      #&&&$.      ",
+"       .@$&&.     ",
+"     .#.  @&@     ",
+"     .&$. #&+     ",
+"      #&&&&$      ",
+"       .+@+       ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *soloOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #3D3F3D",
+"+     c #525451",
+"@     c #666865",
+"#     c #80827F",
+"$     c #979996",
+"%     c #A7A9A6",
+"&     c #C6C8C5",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"       .@@.       ",
+"      #&&&&#      ",
+"     .&$  %&.     ",
+"      &%+ ..      ",
+"      #&&&$+      ",
+"       .@%&&.     ",
+"     +#.  @&@     ",
+"     .&$..#&+     ",
+"      #&&&&$      ",
+"       .@@+       ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+#ifdef WITH_VST
+
+
+const char *fxOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #40423F",
+"+     c #4D4E4C",
+"@     c #686A67",
+"#     c #7B7D7A",
+"$     c #919390",
+"%     c #AEB0AD",
+"&     c #C1C3C0",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"   ..... .   .    ",
+"   $&&&$ $% @&.   ",
+"   $$    .&#&@    ",
+"   $%##.  @&$     ",
+"   $%##.  #&%     ",
+"   $$    .&@&#    ",
+"   $$    %$ @&.   ",
+"   ..    +   +.   ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *fxOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #565855",
+"+     c #636562",
+"@     c #80827F",
+"#     c #8E908D",
+"$     c #9FA19E",
+"%     c #B1B3B0",
+"&     c #C1C3C0",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"   .++++ +.  +.   ",
+"   $&&&$ $% @&.   ",
+"   $$    .&#&@    ",
+"   $%##+  @&$     ",
+"   $%##+  #&%     ",
+"   $$    +&@&#    ",
+"   $$    %$ @&+   ",
+"   ++   .+.  ++   ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *fxShiftUpOff_xpm[] = {
+"18 18 7 1",
+"      c #242523",
+".     c #4D4F4C",
+"+     c #A3A5A2",
+"@     c #868885",
+"#     c #C1C3C0",
+"$     c #313330",
+"%     c #626361",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"       .+@        ",
+"       @+#.       ",
+"      $#%+@       ",
+"      %# %#$      ",
+"      +@ $#%      ",
+"     $#.  @+      ",
+"     $.   $.      ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *fxShiftUpOn_xpm[] = {
+"18 18 5 1",
+"      c #4D4F4C",
+".     c #70726F",
+"+     c #A5A7A4",
+"@     c #C1C3BF",
+"#     c #8E908D",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"       .++        ",
+"       +@@.       ",
+"       @.+#       ",
+"      .@ .@       ",
+"      +#  @.      ",
+"     .@.  #+      ",
+"      .    .      ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *fxShiftDownOff_xpm[] = {
+"18 18 7 1",
+"      c #242523",
+".     c #4D4F4C",
+"+     c #A3A5A2",
+"@     c #313330",
+"#     c #626361",
+"$     c #868885",
+"%     c #C1C3C0",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     .+@  #$      ",
+"     @%#  +$      ",
+"      $+ .%@      ",
+"      .%@$+       ",
+"       +$%#       ",
+"       #%%@       ",
+"       @..        ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *fxShiftDownOn_xpm[] = {
+"18 18 5 1",
+"      c #4D4F4C",
+".     c #70726F",
+"+     c #A5A7A4",
+"@     c #C1C3BF",
+"#     c #8E908D",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     .+   .+      ",
+"      @.  +#      ",
+"      #+ .@.      ",
+"      .@.#+       ",
+"       +#@.       ",
+"       #@@        ",
+"        ..        ",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *vstLogo_xpm[] = {
+"65 38 8 1",
+"      c #161715",
+".     c #2B2D2A",
+"+     c #474846",
+"@     c #6A6C69",
+"#     c #8C8E8B",
+"$     c #A8AAA7",
+"%     c #C7C9C6",
+"&     c #EEF0ED",
+" @#############################################################+ ",
+"@#.............................................................$+",
+"#.                                                             .#",
+"#.                                                             .#",
+"#.                             ......      ..                  .#",
+"#.                         .@$$$####$%$#@.+&$                  .#",
+"#.                       .#$$#+.     +#$%%%%$                  .#",
+"#.                      .$$#$          .#$$%$                  .#",
+"#. .............    ....$$$$$          ++$$%$+@@@@@@@@@@@@@@@  .#",
+"#. ##$$$$$$%%%%@    %%&&&&%%$@         %&@#$$@@$%%&&&%%%&&&&&  .#",
+"#.   +$$$$$%@         .&%####%$@       $&$.$#  #$%%%&    @&%&  .#",
+"#.    +$$$$$%         +&$###$%%&&$@.   $&.     #$%%%&.    .%&  .#",
+"#.     @$$$$%$        %##$##$%&&&&&&%#.%#      #$$%%&.     @&  .#",
+"#.      $$$$$%+      #&  #$$%%&&&&&&&%%$$@     #$$%%&.      +  .#",
+"#.      .$$$$$%     +&+   .#%&&&&&&&&%$$#$$#   #$$%%&.         .#",
+"#.       @$$$$%$    %$       @%&&&&&&%$$###$$  #$$%%&.         .#",
+"#.        #$$$%%@  #&  .        +$&&&%$####$%$ #$$%%&.         .#",
+"#.         $$$%%% .&@ +%#          .@$$$###$$% #$$$%&.         .#",
+"#.         +%$%%%$$%  +$$+             #$#$$$% @$$$%&.         .#",
+"#.          #%%%%%&.  +%$$              ##$$%$ @$$$%%.         .#",
+"#.           $$%%%@   +%$$$.            #$$$%. @$$$$%.         .#",
+"#.           +%%%$    +%$$#$@          +$$%$   @#$$$%+         .#",
+"#.            @%%.    +%%%$$$$#@++.++@#$$$@ @@##$$$%%%$$@      .#",
+"#.             #@     +&#  .@@###$$$###@.   @+++@@@@###$@      .#",
+"#.                                                             .#",
+"#.                                                             .#",
+"#.                                                             .#",
+"#.                                                             .#",
+"#.                                                             .#",
+"#.                   .@$$$$$$$$  .$%%%%%%#                     .#",
+"#.                  .......      .@@@@@@@@@.                   .#",
+"#.                 ........   @@@+@@@@@@@@@@+                  .#",
+"@#                .........  .####@@@@@@@@@@@+                 #@",
+" @$$$$$$$$$$$$$$$..........  .@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$@ ",
+"                  .........  .@@@@@@@@@@@@@@@.                   ",
+"                   ........       @@@@@@@@@@.                    ",
+"                    ...........  .@@@@@@@@@                      ",
+"                     ..........  .@@@@@@@@                       "};
+
+
+const char *fxRemoveOff_xpm[] = {
+"18 18 9 1",
+"      c None",
+".     c #242623",
+"+     c #2F312E",
+"@     c #393A38",
+"#     c #484A47",
+"$     c #5D5F5C",
+"%     c #8E908D",
+"&     c #9B9D9A",
+"*     c #BDBFBC",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+".....+#@..@#+.....",
+"......&*++*&......",
+"......@*%%*@......",
+".......$**$.......",
+".......#**#.......",
+"......+*&&*+......",
+"......%*@@*%......",
+"......@@..@@......",
+"..................",
+"..................",
+"..................",
+"..................",
+".................."};
+
+
+const char *fxRemoveOn_xpm[] = {
+"18 18 9 1",
+"      c None",
+".     c #4D4F4C",
+"+     c #575956",
+"@     c #5C5D5B",
+"#     c #666865",
+"$     c #787977",
+"%     c #9C9E9B",
+"&     c #A6A8A5",
+"*     c #BFC1BE",
+"..................",
+"..................",
+"..................",
+"..................",
+"..................",
+"......#@..@#......",
+"......&*++*&......",
+"......@*%%*@......",
+".......$**$.......",
+".......#**#.......",
+"......+*&&*+......",
+"......%*@+*%......",
+"......@+..+@......",
+"..................",
+"..................",
+"..................",
+"..................",
+".................."};
+#endif // #ifdef WITH_VST
+
+
+const char *beatsDivideOn_xpm[] = {
+"13 13 13 1",
+"      c None",
+".     c #595B58",
+"+     c #5B5D5A",
+"@     c #5F615E",
+"#     c #686967",
+"$     c #737572",
+"%     c #787A77",
+"&     c #80827F",
+"*     c #8F918E",
+"=     c #959794",
+"-     c #9A9C99",
+";     c #C4C6C3",
+">     c #C7C9C6",
+".............",
+".............",
+".............",
+".............",
+".....#>#.....",
+"....+@%@+....",
+"...*>>>>>*...",
+"....+@%@+....",
+".....#>#.....",
+".............",
+".............",
+".............",
+"............."};
+
+
+const char *beatsDivideOff_xpm[] = {
+"13 13 13 1",
+"      c None",
+".     c #242523",
+"+     c #262825",
+"@     c #2D2E2C",
+"#     c #3A3B39",
+"$     c #494B48",
+"%     c #525451",
+"&     c #595B58",
+"*     c #5F615E",
+"=     c #787A77",
+"-     c #858784",
+";     c #C3C5C1",
+">     c #C7C9C6",
+".............",
+".............",
+".............",
+"......+......",
+".....#>#.....",
+"...++@%@++...",
+"...=>>>>>=...",
+"...++@%@++...",
+".....#>#.....",
+"......+......",
+".............",
+".............",
+"............."};
+
+
+const char *beatsMultiplyOn_xpm[] = {
+"13 13 13 1",
+"      c None",
+".     c #595B58",
+"+     c #5B5D5A",
+"@     c #5F615E",
+"#     c #686967",
+"$     c #737572",
+"%     c #787A77",
+"&     c #80827F",
+"*     c #8F918E",
+"=     c #959794",
+"-     c #9A9C99",
+";     c #C4C6C3",
+">     c #C7C9C6",
+".............",
+".............",
+".............",
+"....$...$....",
+"...$;&.&;$...",
+"....&;-;&....",
+".....->-.....",
+"....&;=;&....",
+"...$;&.&;$...",
+"...+$...$....",
+".............",
+".............",
+"............."};
+
+
+const char *beatsMultiplyOff_xpm[] = {
+"13 13 12 1",
+"      c #242523",
+".     c #262825",
+"+     c #2D2E2C",
+"@     c #3A3B39",
+"#     c #494B48",
+"$     c #525451",
+"%     c #595B58",
+"&     c #5F615E",
+"*     c #787A77",
+"=     c #858784",
+"-     c #C3C5C1",
+";     c #C7C9C6",
+"             ",
+"             ",
+"             ",
+"   .#   #.   ",
+"   #-& &-#   ",
+"    &-=-&    ",
+"     =;=     ",
+"    %-*-&    ",
+"   #-% %-#   ",
+"   .#   #.   ",
+"             ",
+"             ",
+"             "};
+
+
+const char *channelStop_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #312D2C",
+"+     c #413A3A",
+"@     c #615253",
+"#     c #73605F",
+"$     c #7A6663",
+"%     c #9C7E7D",
+"&     c #B08D8E",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"     ##.          ",
+"     $&%@         ",
+"     $&&&%+       ",
+"     $&&&&&$.     ",
+"     $&&&&&&&@    ",
+"     $&&&&&&&@.   ",
+"     $&&&&&$.     ",
+"     $&&&%+       ",
+"     $&&@         ",
+"     $#.          ",
+"     .            ",
+"                  ",
+"                  ",
+"                  "};
+
+
+
+const char *channelPlay_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #554E56",
+"+     c #5A4D59",
+"@     c #605068",
+"#     c #775086",
+"$     c #8A509C",
+"%     c #9E50B5",
+"&     c #AD52D0",
+"                  ",
+"                  ",
+"                  ",
+"     .            ",
+"     $$.          ",
+"     $&%#         ",
+"     $&&&%@       ",
+"     $&&&&&$.     ",
+"     $&&&&&&&#.   ",
+"     $&&&&&&&#.   ",
+"     $&&&&&$+     ",
+"     $&&&%@       ",
+"     $&&#         ",
+"     $$.          ",
+"     .            ",
+"                  ",
+"                  ",
+"                  "};
diff --git a/src/core/graphics.h b/src/core/graphics.h
new file mode 100644 (file)
index 0000000..c8d9073
--- /dev/null
@@ -0,0 +1,105 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * graphics
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GRAPHICS_H
+#define GRAPHICS_H
+
+extern const char *giada_logo_xpm[];
+
+extern const char *loopRepeat_xpm[];
+extern const char *loopBasic_xpm[];
+extern const char *loopOnce_xpm[];
+extern const char *loopOnceBar_xpm[];
+extern const char *oneshotBasic_xpm[];
+extern const char *oneshotRetrig_xpm[];
+extern const char *oneshotPress_xpm[];
+extern const char *oneshotEndless_xpm[];
+
+extern const char *updirOff_xpm[];
+extern const char *updirOn_xpm[];
+
+extern const char *pause_xpm[];
+extern const char *play_xpm[];
+
+extern const char *zoomInOff_xpm[];
+extern const char *zoomInOn_xpm[];
+extern const char *zoomOutOff_xpm[];
+extern const char *zoomOutOn_xpm[];
+
+extern const char *scrollLeftOff_xpm[];
+extern const char *scrollLeftOn_xpm[];
+extern const char *scrollRightOff_xpm[];
+extern const char *scrollRightOn_xpm[];
+
+extern const char *rewindOff_xpm[];
+extern const char *rewindOn_xpm[];
+
+extern const char *recOff_xpm[];
+extern const char *recOn_xpm[];
+
+extern const char *metronomeOff_xpm[];
+extern const char *metronomeOn_xpm[];
+
+extern const char *inputRecOn_xpm[];
+extern const char *inputRecOff_xpm[];
+
+extern const char *beatsDivideOn_xpm[];
+extern const char *beatsDivideOff_xpm[];
+extern const char *beatsMultiplyOn_xpm[];
+extern const char *beatsMultiplyOff_xpm[];
+
+extern const char *muteOff_xpm[];
+extern const char *muteOn_xpm[];
+
+extern const char *soloOff_xpm[];
+extern const char *soloOn_xpm[];
+
+extern const char *readActionOn_xpm[];
+extern const char *readActionOff_xpm[];
+
+extern const char *channelStop_xpm[];
+extern const char *channelPlay_xpm[];
+
+#ifdef WITH_VST
+extern const char *fxOff_xpm[];
+extern const char *fxOn_xpm[];
+
+extern const char *fxShiftUpOn_xpm[];
+extern const char *fxShiftUpOff_xpm[];
+extern const char *fxShiftDownOn_xpm[];
+extern const char *fxShiftDownOff_xpm[];
+
+extern const char *fxRemoveOff_xpm[];
+extern const char *fxRemoveOn_xpm[];
+
+extern const char *vstLogo_xpm[];
+#endif
+
+extern const char *giada_icon[];
+
+#endif
diff --git a/src/core/init.cpp b/src/core/init.cpp
new file mode 100644 (file)
index 0000000..1ecbb2d
--- /dev/null
@@ -0,0 +1,201 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * init
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <ctime>
+#include "../utils/log.h"
+#include "../utils/utils.h"
+#include "../utils/gui_utils.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "init.h"
+#include "mixer.h"
+#include "wave.h"
+#include "const.h"
+#include "mixerHandler.h"
+#include "patch.h"
+#include "conf.h"
+#include "pluginHost.h"
+#include "recorder.h"
+#include "midiMapConf.h"
+#include "kernelMidi.h"
+
+
+extern Mixer                      G_Mixer;
+extern bool                               G_audio_status;
+extern bool                               G_quit;
+extern Patch              G_Patch;
+extern Conf          G_Conf;
+extern MidiMapConf   G_MidiMap;
+extern gdMainWindow *mainWin;
+
+#ifdef WITH_VST
+extern PluginHost         G_PluginHost;
+#endif
+
+
+void init_prepareParser()
+{
+       G_Conf.read();
+       G_Patch.setDefault();
+       if (!gLog_init(G_Conf.logMode))
+               gLog("[init] log init failed! Using default stdout\n");
+  time_t t;
+  time (&t);
+       gLog("[init] Giada "VERSIONE" - %s", ctime(&t));
+       gLog("[init] configuration file ready\n");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_prepareKernelAudio()
+{
+       kernelAudio::openDevice(
+               G_Conf.soundSystem,
+               G_Conf.soundDeviceOut,
+               G_Conf.soundDeviceIn,
+               G_Conf.channelsOut,
+               G_Conf.channelsIn,
+               G_Conf.samplerate,
+               G_Conf.buffersize);
+       G_Mixer.init();
+       recorder::init();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_prepareKernelMIDI()
+{
+       kernelMidi::setApi(G_Conf.midiSystem);
+       kernelMidi::openOutDevice(G_Conf.midiPortOut);
+       kernelMidi::openInDevice(G_Conf.midiPortIn);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_prepareMidiMap()
+{
+       G_MidiMap.init();
+       G_MidiMap.setDefault();
+       G_MidiMap.readMap(G_Conf.midiMapPath);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_startGUI(int argc, char **argv)
+{
+       char win_label[32];
+       sprintf(win_label, "%s - %s",
+                                       VERSIONE_STR,
+                                       !strcmp(G_Patch.name, "") ? "(default patch)" : G_Patch.name);
+
+       mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv);
+       mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH);
+
+       /* never update the GUI elements if G_audio_status is bad, segfaults
+        * are around the corner */
+
+       if (G_audio_status)
+               gu_updateControls();
+
+       if (!G_audio_status)
+               gdAlert(
+                       "Your soundcard isn't configured correctly.\n"
+                       "Check the configuration and restart Giada."
+               );
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_startKernelAudio()
+{
+       if (G_audio_status)
+               kernelAudio::startStream();
+
+#ifdef WITH_VST
+       G_PluginHost.allocBuffers();
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void init_shutdown()
+{
+       G_quit = true;
+
+       /* store position and size of the main window for the next startup */
+
+       G_Conf.mainWindowX = mainWin->x();
+       G_Conf.mainWindowY = mainWin->y();
+       G_Conf.mainWindowW = mainWin->w();
+       G_Conf.mainWindowH = mainWin->h();
+
+       /* close any open subwindow, especially before cleaning PluginHost to
+        * avoid mess */
+
+       gu_closeAllSubwindows();
+       gLog("[init] all subwindows closed\n");
+
+       /* write configuration file */
+
+       if (!G_Conf.write())
+               gLog("[init] error while saving configuration file!\n");
+       else
+               gLog("[init] configuration saved\n");
+
+       /* if G_audio_status we close the kernelAudio FIRST, THEN the mixer.
+        * The opposite could cause random segfaults (even now with RtAudio?). */
+
+       if (G_audio_status) {
+               kernelAudio::closeDevice();
+               G_Mixer.close();
+               gLog("[init] Mixer closed\n");
+       }
+
+       recorder::clearAll();
+       gLog("[init] Recorder cleaned up\n");
+
+#ifdef WITH_VST
+       G_PluginHost.freeAllStacks();
+       gLog("[init] Plugin Host cleaned up\n");
+#endif
+
+       gLog("[init] Giada "VERSIONE" closed\n\n");
+       gLog_close();
+}
diff --git a/src/core/init.h b/src/core/init.h
new file mode 100644 (file)
index 0000000..0824f65
--- /dev/null
@@ -0,0 +1,50 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * init
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef INIT_H
+#define INIT_H
+
+
+#include <cstdio>
+#include <stdint.h>
+#ifdef __APPLE__
+       #include <pwd.h>
+#endif
+
+
+void init_prepareParser();
+void init_startGUI(int argc, char **argv);
+void init_prepareKernelAudio();
+void init_prepareKernelMIDI();
+void init_prepareMidiMap();
+void init_startKernelAudio();
+void init_shutdown();
+
+
+#endif
diff --git a/src/core/kernelAudio.cpp b/src/core/kernelAudio.cpp
new file mode 100644 (file)
index 0000000..c31d507
--- /dev/null
@@ -0,0 +1,468 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * KernelAudio
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <vector>
+#include "../utils/log.h"
+#include "../glue/glue.h"
+#include "kernelAudio.h"
+#include "mixer.h"
+
+#include "conf.h"
+
+
+extern Mixer G_Mixer;
+extern Conf  G_Conf;
+extern bool     G_audio_status;
+
+
+namespace kernelAudio {
+
+RtAudio  *system       = NULL;
+unsigned  numDevs      = 0;
+bool             inputEnabled = 0;
+unsigned  realBufsize  = 0;
+int       api          = 0;
+
+int openDevice(
+       int _api,
+       int outDev,
+       int inDev,
+       int outChan,
+       int inChan,
+       int samplerate,
+       int buffersize)
+{
+       api = _api;
+       gLog("[KA] using system 0x%x\n", api);
+#if defined(__linux__)
+       if (api == SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
+               system = new RtAudio(RtAudio::UNIX_JACK);
+       else
+       if (api == SYS_API_ALSA && hasAPI(RtAudio::LINUX_ALSA))
+               system = new RtAudio(RtAudio::LINUX_ALSA);
+       else
+       if (api == SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
+               system = new RtAudio(RtAudio::LINUX_PULSE);
+#elif defined(_WIN32)
+       if (api == SYS_API_DS && hasAPI(RtAudio::WINDOWS_DS))
+               system = new RtAudio(RtAudio::WINDOWS_DS);
+       else
+       if (api == SYS_API_ASIO && hasAPI(RtAudio::WINDOWS_ASIO))
+               system = new RtAudio(RtAudio::WINDOWS_ASIO);
+#elif defined(__APPLE__)
+       if (api == SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE))
+               system = new RtAudio(RtAudio::MACOSX_CORE);
+#endif
+       else {
+               G_audio_status = false;
+               return 0;
+       }
+
+
+
+       //gLog("[KA] %d\n", sizeof(system->rtapi_));
+
+       gLog("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate);
+
+       numDevs = system->getDeviceCount();
+
+       if (numDevs < 1) {
+               gLog("[KA] no devices found with this API\n");
+               closeDevice();
+               G_audio_status = false;
+               return 0;
+       }
+       else {
+               gLog("[KA] %d device(s) found\n", numDevs);
+               for (unsigned i=0; i<numDevs; i++)
+                       gLog("  %d) %s\n", i, getDeviceName(i));
+       }
+
+
+       RtAudio::StreamParameters outParams;
+       RtAudio::StreamParameters inParams;
+
+       if (outDev == DEFAULT_SOUNDDEV_OUT)
+               outParams.deviceId = getDefaultOut();
+       else
+               outParams.deviceId = outDev;
+       outParams.nChannels = 2;
+       outParams.firstChannel = outChan*2; // chan 0=0, 1=2, 2=4, ...
+
+       /* inDevice can be disabled */
+
+       if (inDev != -1) {
+               inParams.deviceId     = inDev;
+               inParams.nChannels    = 2;
+               inParams.firstChannel = inChan*2;   // chan 0=0, 1=2, 2=4, ...
+               inputEnabled = true;
+       }
+       else
+               inputEnabled = false;
+
+
+  RtAudio::StreamOptions options;
+  options.streamName = "Giada";
+  options.numberOfBuffers = 4;
+
+       realBufsize = buffersize;
+
+#if defined(__linux__) || defined(__APPLE__)
+       if (api == SYS_API_JACK) {
+               samplerate = getFreq(outDev, 0);
+               gLog("[KA] JACK in use, freq = %d\n", samplerate);
+               G_Conf.samplerate = samplerate;
+       }
+#endif
+
+       try {
+               if (inDev != -1) {
+                       system->openStream(
+                               &outParams,                                     // output params
+                               &inParams,                                      // input params
+                               RTAUDIO_FLOAT32,                        // audio format
+                               samplerate,                                     // sample rate
+                               &realBufsize,                           // buffer size in byte
+                               &G_Mixer.masterPlay,  // audio callback
+                               NULL,                                                                   // user data (unused)
+                               &options);
+               }
+               else {
+                       system->openStream(
+                               &outParams,                                     // output params
+                               NULL,                                   // input params
+                               RTAUDIO_FLOAT32,                        // audio format
+                               samplerate,                                     // sample rate
+                               &realBufsize,                           // buffer size in byte
+                               &G_Mixer.masterPlay,  // audio callback
+                               NULL,                                                                   // user data (unused)
+                               &options);
+               }
+               G_audio_status = true;
+
+#if defined(__linux__)
+               if (api == SYS_API_JACK)
+                       jackSetSyncCb();
+#endif
+
+               return 1;
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] system init error: %s\n", e.getMessage().c_str());
+               closeDevice();
+               G_audio_status = false;
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int startStream() {
+       try {
+               system->startStream();
+               gLog("[KA] latency = %lu\n", system->getStreamLatency());
+               return 1;
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] Start stream error: %s\n", e.getMessage().c_str());
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int stopStream() {
+       try {
+               system->stopStream();
+               return 1;
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] Stop stream error\n");
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+const char *getDeviceName(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).name.c_str();
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] invalid device ID = %d\n", dev);
+               return NULL;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int closeDevice() {
+       if (system->isStreamOpen()) {
+#if defined(__linux__) || defined(__APPLE__)
+               system->abortStream(); // stopStream seems to lock the thread
+#elif defined(_WIN32)
+               system->stopStream();    // on Windows it's the opposite
+#endif
+               system->closeStream();
+               delete system;
+               system = NULL;
+       }
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+unsigned getMaxInChans(int dev) {
+
+       if (dev == -1) return 0;
+
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).inputChannels;
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] Unable to get input channels\n");
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+unsigned getMaxOutChans(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).outputChannels;
+       }
+       catch (RtAudioError &e) {
+               gLog("[KA] Unable to get output channels\n");
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool isProbed(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).probed;
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+unsigned getDuplexChans(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).duplexChannels;
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool isDefaultIn(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultInput;
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool isDefaultOut(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultOutput;
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int getTotalFreqs(unsigned dev) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.size();
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int    getFreq(unsigned dev, int i) {
+       try {
+               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.at(i);
+       }
+       catch (RtAudioError &e) {
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int getDefaultIn() {
+       return system->getDefaultInputDevice();
+}
+
+int getDefaultOut() {
+       return system->getDefaultOutputDevice();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int    getDeviceByName(const char *name) {
+       for (unsigned i=0; i<numDevs; i++)
+               if (strcmp(name, getDeviceName(i))==0)
+                       return i;
+       return -1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool hasAPI(int API) {
+       std::vector<RtAudio::Api> APIs;
+       RtAudio::getCompiledApi(APIs);
+       for (unsigned i=0; i<APIs.size(); i++)
+               if (APIs.at(i) == API)
+                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+std::string getRtAudioVersion() {
+       return RtAudio::getVersion();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+#ifdef __linux__
+#include <jack/jack.h>
+#include <jack/intclient.h>
+#include <jack/transport.h>
+
+jack_client_t *jackGetHandle() {
+       return (jack_client_t*) system->rtapi_->__HACK__getJackClient();
+}
+
+void jackStart() {
+       if (api == SYS_API_JACK) {
+               jack_client_t *client = jackGetHandle();
+               jack_transport_start(client);
+       }
+}
+
+
+void jackStop() {
+       if (api == SYS_API_JACK) {
+               jack_client_t *client = jackGetHandle();
+               jack_transport_stop(client);
+       }
+}
+
+
+void jackSetSyncCb() {
+       jack_client_t *client = jackGetHandle();
+       jack_set_sync_callback(client, jackSyncCb, NULL);
+       //jack_set_sync_timeout(client, 8);
+}
+
+
+int jackSyncCb(jack_transport_state_t state, jack_position_t *pos,
+               void *arg)
+{
+       switch (state) {
+               case JackTransportStopped:
+                       gLog("[KA] Jack transport stopped, frame=%d\n", pos->frame);
+                       glue_stopSeq(false);  // false = not from GUI
+                       if (pos->frame == 0)
+                               glue_rewindSeq();
+                       break;
+
+               case JackTransportRolling:
+                       gLog("[KA] Jack transport rolling\n");
+                       break;
+
+               case JackTransportStarting:
+                       gLog("[KA] Jack transport starting, frame=%d\n", pos->frame);
+                       glue_startSeq(false);  // false = not from GUI
+                       if (pos->frame == 0)
+                               glue_rewindSeq();
+                       break;
+
+               default:
+                       gLog("[KA] Jack transport [unknown]\n");
+       }
+       return 1;
+}
+
+#endif
+
+}
+
+
diff --git a/src/core/kernelAudio.h b/src/core/kernelAudio.h
new file mode 100644 (file)
index 0000000..a4673f2
--- /dev/null
@@ -0,0 +1,96 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * KernelAudio
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef KERNELAUDIO_H
+#define KERNELAUDIO_H
+
+
+#include "../deps/rtaudio-mod/RtAudio.h"
+#if defined(__linux__)
+       #include <jack/jack.h>
+       #include <jack/intclient.h>
+       #include <jack/transport.h>
+#endif
+
+
+namespace kernelAudio {
+
+       int openDevice(
+                       int api,
+                       int outDev,
+                       int inDev,
+                       int outChan,
+                       int inChan,
+                       int samplerate,
+                       int buffersize);
+       int closeDevice();
+
+       int startStream();
+       int stopStream();
+
+       bool                      isProbed       (unsigned dev);
+       bool                isDefaultIn    (unsigned dev);
+       bool                      isDefaultOut   (unsigned dev);
+       const char *getDeviceName  (unsigned dev);
+       unsigned    getMaxInChans  (int dev);
+       unsigned    getMaxOutChans (unsigned dev);
+       unsigned    getDuplexChans (unsigned dev);
+       int         getTotalFreqs  (unsigned dev);
+       int                                     getFreq        (unsigned dev, int i);
+       int                                     getDeviceByName(const char *name);
+       int         getDefaultOut  ();
+       int         getDefaultIn   ();
+       bool        hasAPI         (int API);
+
+       std::string getRtAudioVersion();
+
+#ifdef __linux__
+       jack_client_t *jackGetHandle();
+       void jackStart();
+       void jackStop();
+       void jackSetSyncCb();
+       int  jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg);
+#endif
+
+       /* *** how to avoid multiple definition of ***
+        * When you declare a variable in a header file, every source file that
+        * includes that header, either directly or indirectly, gets its own
+        * separate copy of the variable. Then when you go to link all the .o
+        * files together, the linker sees that the variable is instantiated
+        * in a bunch of .o files. Make it extern in the header file and
+        * instantiate it in memory.cpp. */
+
+       extern RtAudio  *system;
+       extern unsigned  numDevs;
+       extern bool              inputEnabled;
+       extern unsigned  realBufsize;           // reale bufsize from the soundcard
+       extern int       api;
+}
+
+#endif
diff --git a/src/core/kernelMidi.cpp b/src/core/kernelMidi.cpp
new file mode 100644 (file)
index 0000000..d695ef8
--- /dev/null
@@ -0,0 +1,395 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * KernelMidi
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdio.h>
+#include "../utils/log.h"
+#include "../glue/glue.h"
+#include "kernelMidi.h"
+#include "mixer.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "pluginHost.h"
+#include "conf.h"
+#include "midiMapConf.h"
+
+
+extern bool        G_midiStatus;
+extern Conf        G_Conf;
+extern Mixer       G_Mixer;
+extern MidiMapConf G_MidiMap;
+
+#ifdef WITH_VST
+extern PluginHost  G_PluginHost;
+#endif
+
+
+namespace kernelMidi
+{
+
+int        api         = 0;      // one api for both in & out
+RtMidiOut *midiOut     = NULL;
+RtMidiIn  *midiIn      = NULL;
+unsigned   numOutPorts = 0;
+unsigned   numInPorts  = 0;
+
+cb_midiLearn *cb_learn = NULL;
+void         *cb_data  = NULL;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void startMidiLearn(cb_midiLearn *cb, void *data)
+{
+       cb_learn = cb;
+       cb_data  = data;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void stopMidiLearn()
+{
+       cb_learn = NULL;
+       cb_data  = NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void setApi(int _api)
+{
+       api = api;
+       gLog("[KM] using system 0x%x\n", api);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int openOutDevice(int port)
+{
+       try {
+               midiOut = new RtMidiOut((RtMidi::Api) api, "Giada MIDI Output");
+               G_midiStatus = true;
+  }
+  catch (RtMidiError &error) {
+    gLog("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
+    G_midiStatus = false;
+    return 0;
+  }
+
+       /* print output ports */
+
+       numOutPorts = midiOut->getPortCount();
+  gLog("[KM] %d output MIDI ports found\n", numOutPorts);
+  for (unsigned i=0; i<numOutPorts; i++)
+               gLog("  %d) %s\n", i, getOutPortName(i));
+
+       /* try to open a port, if enabled */
+
+       if (port != -1 && numOutPorts > 0) {
+               try {
+                       midiOut->openPort(port, getOutPortName(port));
+                       gLog("[KM] MIDI out port %d open\n", port);
+
+                       /* for each init command of MidiMap, send the init commands to the
+                       external world. TODO 1 - we shold do that only if there is a map loaded
+                       and available in MidiMap.
+                       TODO 2 - move the map initialization to another function */
+
+                       for(int i=0; i<G_MidiMap.MAX_INIT_COMMANDS; i++) {
+                               if (G_MidiMap.init_messages[i] != 0x0 && G_MidiMap.init_channels[i] != -1) {
+                                       gLog("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", G_MidiMap.init_channels[i], G_MidiMap.init_messages[i]);
+                                       send(G_MidiMap.init_messages[i] | MIDI_CHANS[G_MidiMap.init_channels[i]]);
+                               }
+                       }
+
+                       return 1;
+               }
+               catch (RtMidiError &error) {
+                       gLog("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str());
+                       G_midiStatus = false;
+                       return 0;
+               }
+       }
+       else
+               return 2;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int openInDevice(int port)
+{
+       try {
+               midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input");
+               G_midiStatus = true;
+  }
+  catch (RtMidiError &error) {
+    gLog("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
+    G_midiStatus = false;
+    return 0;
+  }
+
+       /* print input ports */
+
+       numInPorts = midiIn->getPortCount();
+  gLog("[KM] %d input MIDI ports found\n", numInPorts);
+  for (unsigned i=0; i<numInPorts; i++)
+               gLog("  %d) %s\n", i, getInPortName(i));
+
+       /* try to open a port, if enabled */
+
+       if (port != -1 && numInPorts > 0) {
+               try {
+                       midiIn->openPort(port, getInPortName(port));
+                       midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
+                       gLog("[KM] MIDI in port %d open\n", port);
+                       midiIn->setCallback(&callback);
+                       return 1;
+               }
+               catch (RtMidiError &error) {
+                       gLog("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str());
+                       G_midiStatus = false;
+                       return 0;
+               }
+       }
+       else
+               return 2;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool hasAPI(int API)
+{
+       std::vector<RtMidi::Api> APIs;
+       RtMidi::getCompiledApi(APIs);
+       for (unsigned i=0; i<APIs.size(); i++)
+               if (APIs.at(i) == API)
+                       return true;
+       return false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+const char *getOutPortName(unsigned p)
+{
+       try { return midiOut->getPortName(p).c_str(); }
+       catch (RtMidiError &error) { return NULL; }
+}
+
+const char *getInPortName(unsigned p)
+{
+       try { return midiIn->getPortName(p).c_str(); }
+       catch (RtMidiError &error) { return NULL; }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void send(uint32_t data)
+{
+       if (!G_midiStatus)
+               return;
+
+  std::vector<unsigned char> msg(1, getB1(data));
+  msg.push_back(getB2(data));
+  msg.push_back(getB3(data));
+
+       midiOut->sendMessage(&msg);
+       gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void send(int b1, int b2, int b3)
+{
+       if (!G_midiStatus)
+               return;
+
+       std::vector<unsigned char> msg(1, b1);
+
+       if (b2 != -1)
+               msg.push_back(b2);
+       if (b3 != -1)
+               msg.push_back(b3);
+
+       midiOut->sendMessage(&msg);
+       //gLog("[KM] send msg=(%X %X %X)\n", b1, b2, b3);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void callback(double t, std::vector<unsigned char> *msg, void *data)
+{
+       /* 0.8.0 - for now we handle other midi signals (common and real-time
+        * messages) as unknown, for debugging purposes */
+
+       if (msg->size() < 3) {
+               gLog("[KM] MIDI received - unkown signal - size=%d, value=0x", (int) msg->size());
+               for (unsigned i=0; i<msg->size(); i++)
+                       gLog("%X", (int) msg->at(i));
+               gLog("\n");
+               return;
+       }
+
+       /* in this place we want to catch two things: a) note on/note off
+        * from a keyboard and b) knob/wheel/slider movements from a
+        * controller */
+
+       uint32_t input = getIValue(msg->at(0), msg->at(1), msg->at(2));
+       uint32_t chan  = input & 0x0F000000;
+       uint32_t value = input & 0x0000FF00;
+       uint32_t pure  = 0x00;
+       if (!G_Conf.noNoteOff)
+               pure  = input & 0xFFFF0000;   // input without 'value' byte
+       else
+               pure  = input & 0xFFFFFF00;   // input with 'value' byte
+
+       gLog("[KM] MIDI received - 0x%X (chan %d)", input, chan >> 24);
+
+       /* start dispatcher. If midi learn is on don't parse channels, just
+        * learn incoming midi signal. Otherwise process master events first,
+        * then each channel in the stack. This way incoming signals don't
+        * get processed by glue_* when midi learning is on. */
+
+       if (cb_learn)   {
+               gLog("\n");
+               cb_learn(pure, cb_data);
+       }
+       else {
+
+               /* process master events */
+
+               if      (pure == G_Conf.midiInRewind) {
+                       gLog(" >>> rewind (global) (pure=0x%X)", pure);
+                       glue_rewindSeq();
+               }
+               else if (pure == G_Conf.midiInStartStop) {
+                       gLog(" >>> startStop (global) (pure=0x%X)", pure);
+                       glue_startStopSeq();
+               }
+               else if (pure == G_Conf.midiInActionRec) {
+                       gLog(" >>> actionRec (global) (pure=0x%X)", pure);
+                       glue_startStopActionRec();
+               }
+               else if (pure == G_Conf.midiInInputRec) {
+                       gLog(" >>> inputRec (global) (pure=0x%X)", pure);
+                       glue_startStopInputRec(false, false);   // update gui, no popup messages
+               }
+               else if (pure == G_Conf.midiInMetronome) {
+                       gLog(" >>> metronome (global) (pure=0x%X)", pure);
+                       glue_startStopMetronome(false);
+               }
+               else if (pure == G_Conf.midiInVolumeIn) {
+                       float vf = (value >> 8)/127.0f;
+                       gLog(" >>> input volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
+                       glue_setInVol(vf, false);
+               }
+               else if (pure == G_Conf.midiInVolumeOut) {
+                       float vf = (value >> 8)/127.0f;
+                       gLog(" >>> output volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
+                       glue_setOutVol(vf, false);
+               }
+               else if (pure == G_Conf.midiInBeatDouble) {
+                       gLog(" >>> sequencer x2 (global) (pure=0x%X)", pure);
+                       glue_beatsMultiply();
+               }
+               else if (pure == G_Conf.midiInBeatHalf) {
+                       gLog(" >>> sequencer /2 (global) (pure=0x%X)", pure);
+                       glue_beatsDivide();
+               }
+
+               /* process channels */
+
+               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+
+                       Channel *ch = (Channel*) G_Mixer.channels.at(i);
+
+                       if (!ch->midiIn) continue;
+
+                       if      (pure == ch->midiInKeyPress) {
+                               gLog(" >>> keyPress, ch=%d (pure=0x%X)", ch->index, pure);
+                               glue_keyPress(ch, false, false);
+                       }
+                       else if (pure == ch->midiInKeyRel) {
+                               gLog(" >>> keyRel ch=%d (pure=0x%X)", ch->index, pure);
+                               glue_keyRelease(ch, false, false);
+                       }
+                       else if (pure == ch->midiInMute) {
+                               gLog(" >>> mute ch=%d (pure=0x%X)", ch->index, pure);
+                               glue_setMute(ch, false);
+                       }
+                       else if (pure == ch->midiInSolo) {
+                               gLog(" >>> solo ch=%d (pure=0x%X)", ch->index, pure);
+                               ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false);
+                       }
+                       else if (pure == ch->midiInVolume) {
+                               float vf = (value >> 8)/127.0f;
+                               gLog(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
+                               glue_setChanVol(ch, vf, false);
+                       }
+                       else if (pure == ((SampleChannel*)ch)->midiInPitch) {
+                               float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0]
+                               gLog(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
+                               glue_setPitch(NULL, (SampleChannel*)ch, vf, false);
+                       }
+                       else if (pure == ((SampleChannel*)ch)->midiInReadActions) {
+                               gLog(" >>> start/stop read actions ch=%d (pure=0x%X)", ch->index, pure);
+                               glue_startStopReadingRecs((SampleChannel*)ch, false);
+                       }
+               }
+               gLog("\n");
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string getRtMidiVersion()
+{
+       return midiOut->getVersion();
+}
+
+
+}  // namespace
diff --git a/src/core/kernelMidi.h b/src/core/kernelMidi.h
new file mode 100644 (file)
index 0000000..d446995
--- /dev/null
@@ -0,0 +1,104 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * KernelMidi
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef KERNELMIDI_H
+#define KERNELMIDI_H
+
+
+#include <stdint.h>
+#include <RtMidi.h>
+#include "channel.h"
+
+
+namespace kernelMidi {
+
+       extern int      api;      // one api for both in & out
+       extern unsigned numOutPorts;
+       extern unsigned numInPorts;
+
+       typedef void (cb_midiLearn) (uint32_t, void *);
+
+       /* cb_learn
+        * callback prepared by the gdMidiGrabber window and called by
+        * kernelMidi. It contains things to do once the midi message has been
+        * stored. */
+
+       extern cb_midiLearn *cb_learn;
+       extern void         *cb_data;
+
+       void startMidiLearn(cb_midiLearn *cb, void *data);
+       void stopMidiLearn();
+
+       inline int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; }
+       inline int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; }
+       inline int getB3(uint32_t iValue) { return (iValue >> 8)  & 0xFF; }
+
+       inline uint32_t getIValue(int b1, int b2, int b3) {
+               return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00);
+       }
+
+       /* send
+        * send a MIDI message 's' (uint32_t). */
+
+       void send(uint32_t s);
+
+       /* send (2)
+        * send separate bytes of MIDI message. */
+
+       void send(int b1, int b2=-1, int b3=-1);
+
+       /* setApi
+        * set the Api in use for both in & out messages. */
+
+       void setApi(int api);
+
+       /* open/close/in/outDevice */
+
+       int openOutDevice(int port);
+       int openInDevice(int port);
+       int closeInDevice();
+       int closeOutDevice();
+
+       /* getIn/OutPortName
+        * return the name of the port 'p'. */
+
+       const char *getInPortName(unsigned p);
+       const char *getOutPortName(unsigned p);
+
+       bool hasAPI(int API);
+
+       /* callback
+        * master callback for input events. */
+
+       void callback(double t, std::vector<unsigned char> *msg, void *data);
+
+       std::string getRtMidiVersion();
+}
+
+#endif
diff --git a/src/core/midiChannel.cpp b/src/core/midiChannel.cpp
new file mode 100644 (file)
index 0000000..dfb95f8
--- /dev/null
@@ -0,0 +1,348 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../utils/log.h"
+#include "midiChannel.h"
+#include "channel.h"
+#include "pluginHost.h"
+#include "patch.h"
+#include "conf.h"
+#include "kernelMidi.h"
+
+
+extern Patch       G_Patch;
+extern Mixer       G_Mixer;
+extern Conf        G_Conf;
+#ifdef WITH_VST
+extern PluginHost  G_PluginHost;
+#endif
+
+
+MidiChannel::MidiChannel(int bufferSize)
+       : Channel    (CHANNEL_MIDI, STATUS_OFF, bufferSize),
+         midiOut    (false),
+         midiOutChan(MIDI_CHANS[0])
+{
+#ifdef WITH_VST // init VstEvents stack
+       freeVstMidiEvents(true);
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+MidiChannel::~MidiChannel() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+void MidiChannel::freeVstMidiEvents(bool init)
+{
+       if (events.numEvents == 0 && !init)
+               return;
+       memset(events.events, 0, sizeof(VstEvent*) * MAX_VST_EVENTS);
+       events.numEvents = 0;
+       events.reserved  = 0;
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+void MidiChannel::addVstMidiEvent(uint32_t msg)
+{
+       addVstMidiEvent(G_PluginHost.createVstMidiEvent(msg));
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+void MidiChannel::addVstMidiEvent(VstMidiEvent *e)
+{
+       if (events.numEvents < MAX_VST_EVENTS) {
+               events.events[events.numEvents] = (VstEvent*) e;
+               events.numEvents++;
+               /*
+               gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n",
+                       events.numEvents,
+                       e->deltaFrames,
+                       e->midiData[0],
+                       e->midiData[1],
+                       e->midiData[2]
+               );*/
+       }
+       else
+               gLog("[MidiChannel] channel %d VstEvents = %d > MAX_VST_EVENTS, nothing to do\n", index, events.numEvents);
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::onBar(int frame) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::stop() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::empty() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::quantize(int index, int localFrame, int globalFrame) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef WITH_VST
+
+VstEvents *MidiChannel::getVstEvents()
+{
+       return (VstEvents *) &events;
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
+{
+       if (a->type == ACTION_MIDI)
+               sendMidi(a, localFrame/2);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::onZero(int frame)
+{
+       if (status == STATUS_ENDING) {
+               status = STATUS_OFF;
+               sendMidiLplay();
+       }
+       else
+       if (status == STATUS_WAIT) {
+               status = STATUS_PLAY;
+               sendMidiLplay();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::setMute(bool internal)
+{
+       mute = true;    // internal mute does not exist for midi (for now)
+       if (midiOut)
+               kernelMidi::send(MIDI_ALL_NOTES_OFF);
+#ifdef WITH_VST
+               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
+#endif
+       sendMidiLmute();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::unsetMute(bool internal)
+{
+       mute = false;   // internal mute does not exist for midi (for now)
+       sendMidiLmute();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::process(float *buffer)
+{
+#ifdef WITH_VST
+       G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
+       freeVstMidiEvents();
+#endif
+
+       for (int j=0; j<bufferSize; j+=2) {
+               buffer[j]   += vChan[j]   * volume; // * panLeft;   future?
+               buffer[j+1] += vChan[j+1] * volume; // * panRight;  future?
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::start(int frame, bool doQuantize)
+{
+       switch (status) {
+               case STATUS_PLAY:
+                       status = STATUS_ENDING;
+                       sendMidiLplay();
+                       break;
+               case STATUS_ENDING:
+               case STATUS_WAIT:
+                       status = STATUS_OFF;
+                       sendMidiLplay();
+                       break;
+               case STATUS_OFF:
+                       status = STATUS_WAIT;
+                       sendMidiLplay();
+                       break;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::stopBySeq()
+{
+       kill(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::kill(int frame)
+{
+       if (status & (STATUS_PLAY | STATUS_ENDING)) {
+               if (midiOut)
+                       kernelMidi::send(MIDI_ALL_NOTES_OFF);
+#ifdef WITH_VST
+               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
+#endif
+       }
+       status = STATUS_OFF;
+       sendMidiLplay();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int MidiChannel::loadByPatch(const char *f, int i)
+{
+       volume      = G_Patch.getVol(i);
+       index       = G_Patch.getIndex(i);
+       mute        = G_Patch.getMute(i);
+       mute_s      = G_Patch.getMute_s(i);
+       solo        = G_Patch.getSolo(i);
+       panLeft     = G_Patch.getPanLeft(i);
+       panRight    = G_Patch.getPanRight(i);
+
+       midiOut     = G_Patch.getMidiValue(i, "Out");
+       midiOutChan = G_Patch.getMidiValue(i, "OutChan");
+
+       readPatchMidiIn(i);
+       readPatchMidiOut(i);
+
+       return SAMPLE_LOADED_OK;  /// TODO - change name, it's meaningless here
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::sendMidi(recorder::action *a, int localFrame)
+{
+       if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
+               if (midiOut)
+                       kernelMidi::send(a->iValue | MIDI_CHANS[midiOutChan]);
+
+#ifdef WITH_VST
+               a->event->deltaFrames = localFrame;
+               addVstMidiEvent(a->event);
+#endif
+       }
+}
+
+
+void MidiChannel::sendMidi(uint32_t data)
+{
+       if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
+               if (midiOut)
+                       kernelMidi::send(data | MIDI_CHANS[midiOutChan]);
+#ifdef WITH_VST
+               addVstMidiEvent(data);
+#endif
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::rewind()
+{
+       if (midiOut)
+               kernelMidi::send(MIDI_ALL_NOTES_OFF);
+#ifdef WITH_VST
+               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::writePatch(FILE *fp, int i, bool isProject)
+{
+       Channel::writePatch(fp, i, isProject);
+
+       fprintf(fp, "chanMidiOut%d=%u\n",        i, midiOut);
+       fprintf(fp, "chanMidiOutChan%d=%u\n",    i, midiOutChan);
+}
diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h
new file mode 100644 (file)
index 0000000..275081c
--- /dev/null
@@ -0,0 +1,139 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * channel
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef MIDI_CHANNEL_H
+#define MIDI_CHANNEL_H
+
+
+#include "channel.h"
+
+
+#ifdef WITH_VST
+
+/* before including aeffetx(x).h we must define __cdecl, otherwise VST
+ * headers can't be compiled correctly. In windows __cdecl is already
+ * defined. */
+
+       #ifdef __GNUC__
+               #ifndef _WIN32
+                       #define __cdecl
+               #endif
+       #endif
+       #include "../deps/vst/aeffectx.h"
+
+#endif
+
+
+class MidiChannel : public Channel {
+
+public:
+
+       MidiChannel(int bufferSize);
+       ~MidiChannel();
+
+  bool    midiOut;           // enable midi output
+  uint8_t midiOutChan;       // midi output channel
+
+       void  process    (float *buffer);
+       void  start      (int frame, bool doQuantize);
+       void  kill       (int frame);
+       void  empty      ();
+       void  stopBySeq  ();
+       void  stop       ();
+       void  rewind     ();
+       void  setMute    (bool internal);
+       void  unsetMute  (bool internal);
+       int   loadByPatch(const char *file, int i);
+       void  writePatch (FILE *fp, int i, bool isProject);
+       void  quantize   (int index, int localFrame, int globalFrame);
+       void  onZero     (int frame);
+       void  onBar      (int frame);
+       void  parseAction(recorder::action *a, int localFrame, int globalFrame);
+
+       /* ---------------------------------------------------------------- */
+
+       /* sendMidi
+        * send Midi event to the outside world. */
+
+       void sendMidi(recorder::action *a, int localFrame);
+       void sendMidi(uint32_t data);
+
+#ifdef WITH_VST
+
+       /* getVstEvents
+        * return a pointer to gVstEvents. */
+
+       VstEvents *getVstEvents();
+
+       /* freeVstMidiEvents
+        * empty vstEvents structure. Init: use the method for channel
+        * initialization. */
+
+       void freeVstMidiEvents(bool init=false);
+
+       /* addVstMidiEvent
+        * take a composite MIDI event, decompose it and add it to channel. The
+        * other version creates a VstMidiEvent on the fly. */
+
+       void addVstMidiEvent(struct VstMidiEvent *e);
+       void addVstMidiEvent(uint32_t msg);
+
+#endif
+
+       /* ---------------------------------------------------------------- */
+
+#ifdef WITH_VST
+
+       /* VST struct containing MIDI events. When ready, events are sent to
+        * each plugin in the channel.
+        *
+        * Anatomy of VstEvents
+        * --------------------
+        *
+        * VstInt32  numEvents = number of Events in array
+        * VstIntPtr reserved  = zero (Reserved for future use)
+        * VstEvent *events[n] = event pointer array, variable size
+        *
+        * Note that by default VstEvents only holds three events- if you want
+        * it to hold more, create an equivalent struct with a larger array,
+        * and then cast it to a VstEvents object when you've populated it.
+        * That's what we do with gVstEvents! */
+
+       struct gVstEvents {
+    VstInt32  numEvents;
+    VstIntPtr reserved;
+    VstEvent *events[MAX_VST_EVENTS];
+       } events;
+
+#endif
+
+};
+
+
+#endif
diff --git a/src/core/midiMapConf.cpp b/src/core/midiMapConf.cpp
new file mode 100644 (file)
index 0000000..9a0dfc5
--- /dev/null
@@ -0,0 +1,223 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * midiMapConf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <dirent.h>
+#include "midiMapConf.h"
+#include "const.h"
+#include "../utils/utils.h"
+#include "../utils/log.h"
+
+
+using std::string;
+
+
+void MidiMapConf::init()
+{
+       midimapsPath = gGetHomePath() + "/midimaps/";
+
+       /* scan dir of midi maps and load the filenames into <>maps. */
+
+       gLog("[MidiMapConf::init] scanning midimaps directory...\n");
+
+  DIR    *dp;
+  dirent *ep;
+  dp = opendir(midimapsPath.c_str());
+
+       if (!dp) {
+               gLog("[MidiMapConf::init] unable to scan midimaps directory!\n");
+               return;
+       }
+
+       while ((ep = readdir(dp))) {
+               if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+                       continue;
+
+               // TODO - check if is a valid midimap file (verify headers)
+
+               gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name);
+
+               maps.add(ep->d_name);
+       }
+
+       closedir(dp);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::setDefault()
+{
+       brand  = "";
+       device = "";
+
+       for (int i=0; i<MAX_INIT_COMMANDS; i++) {
+               init_channels[i] = -1;
+               init_messages[i] = 0x00;
+       }
+
+       muteOnChan     = 0;
+       muteOnOffset   = 0;
+       muteOnMsg      = 0;
+
+       muteOffChan    = 0;
+       muteOffOffset  = 0;
+       muteOffMsg     = 0;
+
+       soloOnChan     = 0;
+       soloOnOffset   = 0;
+       soloOnMsg      = 0;
+
+       soloOffChan    = 0;
+       soloOffOffset  = 0;
+       soloOffMsg     = 0;
+
+       waitingChan    = 0;
+       waitingOffset  = 0;
+       waitingMsg     = 0;
+
+       playingChan    = 0;
+       playingOffset  = 0;
+       playingMsg     = 0;
+
+       stoppingChan   = 0;
+       stoppingOffset = 0;
+       stoppingMsg    = 0;
+
+       stoppedChan    = 0;
+       stoppedOffset  = 0;
+       stoppedMsg     = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int MidiMapConf::readMap(string file)
+{
+       if (file.empty()) {
+               gLog("[MidiMapConf::readFromFile] midimap not specified, nothing to do\n");
+               return 0;
+       }
+
+       gLog("[MidiMapConf::readFromFile] reading midimap file '%s'\n", file.c_str());
+
+       string path = midimapsPath + file;
+       fp = fopen(path.c_str(), "r");
+       if (!fp) {
+               gLog("[MidiMapConf::readFromFile] unreadable midimap file\n");
+               return 0;
+       }
+
+       brand  = getValue("brand");
+       device = getValue("device");
+
+       gLog("[MidiMapConf::readFromFile] reading midimap for %s %s\n",
+                       brand.c_str(), device.c_str());
+
+       /* parse init commands */
+
+       gVector<string> ic;
+       gSplit(getValue("init_commands"), ";", &ic);
+       for (unsigned i=0; i<(unsigned)MAX_INIT_COMMANDS && i<ic.size; i++) {
+               sscanf(ic.at(i).c_str(), "%d:%x", &init_channels[i], &init_messages[i]);
+               gLog("[MidiMapConf::readFromFile] init command %d - channel %d - message 0x%X\n",
+                               i, init_channels[i], init_messages[i]);
+       }
+
+       /* parse messages */
+
+       parse("mute_on",  &muteOnChan,   &muteOnMsg,   &muteOnOffset);
+       parse("mute_off", &muteOffChan,  &muteOffMsg,  &muteOffOffset);
+       parse("solo_on",  &soloOnChan,   &soloOnMsg,   &soloOnOffset);
+       parse("solo_off", &soloOffChan,  &soloOffMsg,  &soloOffOffset);
+       parse("waiting",  &waitingChan,  &waitingMsg,  &waitingOffset);
+       parse("playing",  &playingChan,  &playingMsg,  &playingOffset);
+       parse("stopping", &stoppingChan, &stoppingMsg, &stoppingOffset);
+       parse("stopped",  &stoppedChan,  &stoppedMsg,  &stoppedOffset);
+
+       close();
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::close()
+{
+       if (fp != NULL)
+               fclose(fp);
+       fp = NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::parse(string key, int *chan, uint32_t *msg, int *offset)
+{
+       gLog("[MidiMapConf::parse2] command %s - ", key.c_str());
+       string value = getValue(key.c_str());
+
+       /* grab channel part, i.e. [channel]:*/
+
+       *chan = atoi(value.substr(0, value.find(':')).c_str());
+
+       /* grab MIDI part :[midi-message] and search for 'nn' note placeholder within.
+        * Note: when using 'string::npos' as the value for a len (or sublen)
+        * parameter in string's member functions, means "until the end of the
+        * string". */
+
+       string midiParts = value.substr(value.find(':')+3, string::npos);
+
+       char strmsg[MAX_MIDI_NIBBLES];
+       *offset = 0;
+
+       /* build the message as a string, for each char (i.e. nibble) in the
+        * original string. Substitute 'n' with zeros. */
+
+       for (unsigned i=0, p=24; i<(unsigned)MAX_MIDI_NIBBLES; i++, p-=4) {
+               if (midiParts[i] == 'n') {
+                       strmsg[i] = '0';
+                       if (*offset == 0)
+                               *offset = p;
+               }
+               else
+                       strmsg[i] = midiParts[i];
+       }
+
+       *msg = strtoul(strmsg, NULL, 16);  // from string to uint32_t
+
+       gLog("chan=%d value=%s msg=%#x, offset=%d\n", *chan, midiParts.c_str(), *msg, *offset);
+}
diff --git a/src/core/midiMapConf.h b/src/core/midiMapConf.h
new file mode 100644 (file)
index 0000000..d56795a
--- /dev/null
@@ -0,0 +1,133 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * midiMapConf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __MIDIMAPCONF_H__
+#define __MIDIMAPCONF_H__
+
+
+#include <limits.h>
+#include <stdint.h>
+#include "dataStorage.h"
+#include "../utils/utils.h"
+#if defined(__APPLE__)
+#include <pwd.h>
+#endif
+
+
+using std::string;
+
+
+class MidiMapConf : public DataStorage
+{
+private:
+
+       void close();
+       void parse(string key, int *chan, uint32_t *msg, int *offset);
+
+public:
+
+       static const int MAX_INIT_COMMANDS = 32;
+       static const int MAX_MIDI_BYTES = 4;
+       static const int MAX_MIDI_NIBBLES = 8;
+
+       /* midimapsPath
+        * path of midimap files, different between OSes. */
+
+       string midimapsPath;
+
+       /* maps
+        * Maps are the available .giadamap files. Each element of the vector
+        * represents a .giadamap filename. */
+
+       gVector<string> maps;
+
+       string brand;
+       string device;
+
+       /* init_*
+        * init_commands. These messages are sent to the physical device as a wake up
+        * signal. */
+
+       int      init_channels[MAX_INIT_COMMANDS];
+       uint32_t init_messages[MAX_INIT_COMMANDS];
+
+       /* events
+        * [event]Channel: the MIDI output channel to send the event to
+        * [event]notePos: the byte where the note is stored ('nn' placeholder)
+        * [event]offset:  the note offset (i.e. of 'nn' placeholder) */
+
+       int      muteOnChan;
+       int      muteOnOffset;
+       uint32_t muteOnMsg;
+
+       int      muteOffChan;
+       int      muteOffOffset;
+       uint32_t muteOffMsg;
+
+       int      soloOnChan;
+       int      soloOnOffset;
+       uint32_t soloOnMsg;
+
+       int      soloOffChan;
+       int      soloOffOffset;
+       uint32_t soloOffMsg;
+
+       int      waitingChan;
+       int      waitingOffset;
+       uint32_t waitingMsg;
+
+       int      playingChan;
+       int      playingOffset;
+       uint32_t playingMsg;
+
+       int      stoppingChan;
+       int      stoppingOffset;
+       uint32_t stoppingMsg;
+
+       int      stoppedChan;
+       int      stoppedOffset;
+       uint32_t stoppedMsg;
+
+       /* init
+       Parse the midi maps folders and find the available maps. */
+
+       void init();
+
+       /* setDefault
+       Set default values in case no maps are available/choosen. */
+
+       void setDefault();
+
+       /* readMap
+       Read a midi map from file 'file'. */
+
+       int readMap(string file);
+};
+
+#endif
diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp
new file mode 100644 (file)
index 0000000..2930f81
--- /dev/null
@@ -0,0 +1,684 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * mixer
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <math.h>
+#include "../utils/log.h"
+#include "../utils/gui_utils.h"
+#include "mixer.h"
+#include "init.h"
+#include "wave.h"
+#include "recorder.h"
+#include "pluginHost.h"
+#include "patch.h"
+#include "conf.h"
+#include "mixerHandler.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "midiChannel.h"
+#include "kernelMidi.h"
+
+
+extern Mixer                    G_Mixer;
+extern Patch                    G_Patch;
+extern Conf                             G_Conf;
+#ifdef WITH_VST
+extern PluginHost  G_PluginHost;
+#endif
+
+
+Mixer::Mixer()         {}
+Mixer::~Mixer() {}
+
+
+#define TICKSIZE 38
+
+
+float Mixer::tock[TICKSIZE] = {
+        0.059033,  0.117240,  0.173807,  0.227943,  0.278890,  0.325936,
+        0.368423,  0.405755,  0.437413,  0.462951,  0.482013,  0.494333,
+        0.499738,  0.498153,  0.489598,  0.474195,  0.452159,  0.423798,
+        0.389509,  0.349771,  0.289883,  0.230617,  0.173194,  0.118739,
+        0.068260,  0.022631, -0.017423, -0.051339,     -0.078721, -0.099345,
+       -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
+       -0.070862, -0.048844
+};
+
+
+float Mixer::tick[TICKSIZE] = {
+         0.175860,  0.341914,  0.488904,  0.608633,  0.694426,  0.741500,
+         0.747229,  0.711293,  0.635697,  0.524656,  0.384362,  0.222636,
+         0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
+        -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
+        -0.201360, -0.067752,  0.052194,  0.151746,  0.226280,  0.273493,
+         0.293425,  0.288307,  0.262252,  0.220811,  0.170435,  0.117887,
+         0.069639,  0.031320
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::init() {
+       quanto      = 1;
+       docross     = false;
+       rewindWait  = false;
+       running     = false;
+       ready       = true;
+       waitRec     = 0;
+       actualFrame = 0;
+       bpm                 = DEFAULT_BPM;
+       bars                = DEFAULT_BARS;
+       beats               = DEFAULT_BEATS;
+       quantize    = DEFAULT_QUANTIZE;
+       metronome   = false;
+
+       tickTracker = 0;
+       tockTracker = 0;
+       tickPlay    = false;
+       tockPlay    = false;
+
+       outVol       = DEFAULT_OUT_VOL;
+       inVol        = DEFAULT_IN_VOL;
+       peakOut      = 0.0f;
+       peakIn       = 0.0f;
+       chanInput    = NULL;
+       inputTracker = 0;
+
+       actualBeat    = 0;
+
+       midiTCstep    = 0;
+       midiTCrate    = (G_Conf.samplerate / G_Conf.midiTCfps) * 2;  // dealing with stereo vals
+       midiTCframes  = 0;
+       midiTCseconds = 0;
+       midiTCminutes = 0;
+       midiTChours   = 0;
+
+       /* alloc virtual input channels. vChanInput malloc is done in
+        * updateFrameBars, because of its variable size */
+       /** TODO - set kernelAudio::realBufsize * 2 as private member */
+
+       vChanInput   = NULL;
+       vChanInToOut = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
+
+       pthread_mutex_init(&mutex_recs, NULL);
+       pthread_mutex_init(&mutex_chans, NULL);
+       pthread_mutex_init(&mutex_plugins, NULL);
+
+       updateFrameBars();
+       rewind();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Channel *Mixer::addChannel(int type) {
+
+       Channel *ch;
+       int bufferSize = kernelAudio::realBufsize*2;
+
+       if (type == CHANNEL_SAMPLE)
+               ch = new SampleChannel(bufferSize);
+       else
+               ch = new MidiChannel(bufferSize);
+
+       while (true) {
+               int lockStatus = pthread_mutex_trylock(&mutex_chans);
+               if (lockStatus == 0) {
+                       channels.add(ch);
+                       pthread_mutex_unlock(&mutex_chans);
+                       break;
+               }
+       }
+
+       ch->index = getNewIndex();
+       gLog("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size);
+       return ch;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Mixer::getNewIndex() {
+
+       /* always skip last channel: it's the last one just added */
+
+       if (channels.size == 1)
+               return 0;
+
+       int index = 0;
+       for (unsigned i=0; i<channels.size-1; i++) {
+               if (channels.at(i)->index > index)
+                       index = channels.at(i)->index;
+               }
+       index += 1;
+       return index;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Mixer::deleteChannel(Channel *ch) {
+       int lockStatus;
+       while (true) {
+               lockStatus = pthread_mutex_trylock(&mutex_chans);
+               if (lockStatus == 0) {
+                       channels.del(ch);
+                       delete ch;
+                       pthread_mutex_unlock(&mutex_chans);
+                       return 1;
+               }
+               //else
+               //      gLog("[mixer::deleteChannel] waiting for mutex...\n");
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Channel *Mixer::getChannelByIndex(int index) {
+       for (unsigned i=0; i<channels.size; i++)
+               if (channels.at(i)->index == index)
+                       return channels.at(i);
+       gLog("[mixer::getChannelByIndex] channel at index %d not found!\n", index);
+       return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::sendMIDIsync() {
+
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
+               if (actualFrame % (framesPerBeat/24) == 0)
+                       kernelMidi::send(MIDI_CLOCK, -1, -1);
+       }
+       else
+       if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
+
+               /* check if a new timecode frame has passed. If so, send MIDI TC
+                * quarter frames. 8 quarter frames, divided in two branches:
+                * 1-4 and 5-8. We check timecode frame's parity: if even, send
+                * range 1-4, if odd send 5-8. */
+
+               if (actualFrame % midiTCrate == 0) {
+
+                       /* frame low nibble
+                        * frame high nibble
+                        * seconds low nibble
+                        * seconds high nibble */
+
+                       if (midiTCframes % 2 == 0) {
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F)  | 0x00, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4)    | 0x10, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4)   | 0x30, -1);
+                       }
+
+                       /* minutes low nibble
+                        * minutes high nibble
+                        * hours low nibble
+                        * hours high nibble SMPTE frame rate */
+
+                       else {
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4)   | 0x50, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F)   | 0x60, -1);
+                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4)     | 0x70, -1);
+                       }
+
+                       midiTCframes++;
+
+                       /* check if total timecode frames are greater than timecode fps:
+                        * if so, a second has passed */
+
+                       if (midiTCframes > G_Conf.midiTCfps) {
+                               midiTCframes = 0;
+                               midiTCseconds++;
+                               if (midiTCseconds >= 60) {
+                                       midiTCminutes++;
+                                       midiTCseconds = 0;
+                                       if (midiTCminutes >= 60) {
+                                               midiTChours++;
+                                               midiTCminutes = 0;
+                                       }
+                               }
+                               //gLog("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes);
+                       }
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::sendMIDIrewind() {
+
+       midiTCframes  = 0;
+       midiTCseconds = 0;
+       midiTCminutes = 0;
+       midiTChours   = 0;
+
+       /* For cueing the slave to a particular start point, Quarter Frame
+        * messages are not used. Instead, an MTC Full Frame message should
+        * be sent. The Full Frame is a SysEx message that encodes the entire
+        * SMPTE time in one message */
+
+       if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
+               kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00);  // send msg on channel 0
+               kernelMidi::send(0x01, 0x01, 0x00);        // hours 0
+               kernelMidi::send(0x00, 0x00, 0x00);        // mins, secs, frames 0
+               kernelMidi::send(MIDI_EOX, -1, -1);        // end of sysex
+       }
+}
+
+/* ------------------------------------------------------------------ */
+
+
+int Mixer::masterPlay(
+       void *out_buf, void *in_buf, unsigned n_frames,
+       double streamTime, RtAudioStreamStatus status, void *userData) {
+       return G_Mixer.__masterPlay(out_buf, in_buf, n_frames);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) {
+
+       if (!ready)
+               return 0;
+
+       float *outBuf = ((float *) out_buf);
+       float *inBuf  = ((float *) in_buf);
+       bufferFrames *= 2;     // stereo
+       peakOut       = 0.0f;  // reset peak calculator
+       peakIn        = 0.0f;  // reset peak calculator
+
+       /* always clean each buffer */
+
+       memset(outBuf, 0, sizeof(float) * bufferFrames);         // out
+       memset(vChanInToOut, 0, sizeof(float) * bufferFrames);   // inToOut vChan
+
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned i=0; i<channels.size; i++)
+               if (channels.at(i)->type == CHANNEL_SAMPLE)
+                       ((SampleChannel*)channels.at(i))->clear();
+       pthread_mutex_unlock(&mutex_chans);
+
+       for (unsigned j=0; j<bufferFrames; j+=2) {
+
+               if (kernelAudio::inputEnabled) {
+
+                       /* input peak calculation (left chan only so far). */
+
+                       if (inBuf[j] * inVol > peakIn)
+                               peakIn = inBuf[j] * inVol;
+
+                       /* "hear what you're playing" - process, copy and paste the input buffer
+                        * onto the output buffer */
+
+                       if (inToOut) {
+                               vChanInToOut[j]   = inBuf[j]   * inVol;
+                               vChanInToOut[j+1] = inBuf[j+1] * inVol;
+                       }
+               }
+
+               /* operations to do if the sequencer is running:
+                * - compute quantizer
+                * - time check for LOOP_REPEAT
+                * - reset loops at beat 0
+                * - read recorded actions
+                * - reset actualFrame */
+
+               if (running) {
+
+                       /* line in recording */
+
+                       if (chanInput != NULL && kernelAudio::inputEnabled) {
+
+                               /* delay comp: wait until waitRec reaches delayComp. WaitRec
+                                * returns to 0 in mixerHandler, as soon as the recording ends */
+
+                               if (waitRec < G_Conf.delayComp)
+                                       waitRec += 2;
+                               else {
+                                       vChanInput[inputTracker]   += inBuf[j]   * inVol;
+                                       vChanInput[inputTracker+1] += inBuf[j+1] * inVol;
+                                       inputTracker += 2;
+                                       if (inputTracker >= totalFrames)
+                                               inputTracker = 0;
+                               }
+                       }
+
+                       /* quantizer computations: quantize rewind and all channels. */
+
+                       if (quantize > 0 && quanto > 0) {
+                               if (actualFrame % (quanto) == 0) {   // is quanto!
+                                       if (rewindWait) {
+                                               rewindWait = false;
+                                               rewind();
+                                       }
+                                       pthread_mutex_lock(&mutex_chans);
+                                       for (unsigned k=0; k<channels.size; k++)
+                                               channels.at(k)->quantize(k, j, actualFrame);  // j == localFrame
+                                       pthread_mutex_unlock(&mutex_chans);
+                               }
+                       }
+
+                       /* reset LOOP_REPEAT, if a bar has passed */
+
+                       if (actualFrame % framesPerBar == 0 && actualFrame != 0) {
+                               if (metronome)
+                                       tickPlay = true;
+
+                               pthread_mutex_lock(&mutex_chans);
+                               for (unsigned k=0; k<channels.size; k++)
+                                       channels.at(k)->onBar(j);
+                               pthread_mutex_unlock(&mutex_chans);
+                       }
+
+                       /* reset loops on beat 0 */
+
+                       if (actualFrame == 0) {
+                               pthread_mutex_lock(&mutex_chans);
+                               for (unsigned k=0; k<channels.size; k++)
+                                       channels.at(k)->onZero(j);
+                               pthread_mutex_unlock(&mutex_chans);
+                       }
+
+                       /* reading all actions recorded */
+
+                       pthread_mutex_lock(&mutex_recs);
+                       for (unsigned y=0; y<recorder::frames.size; y++) {
+                               if (recorder::frames.at(y) == actualFrame) {
+                                       for (unsigned z=0; z<recorder::global.at(y).size; z++) {
+                                               int index   = recorder::global.at(y).at(z)->chan;
+                                               Channel *ch = getChannelByIndex(index);
+                                               ch->parseAction(recorder::global.at(y).at(z), j, actualFrame);
+                                       }
+                                       break;
+                               }
+                       }
+                       pthread_mutex_unlock(&mutex_recs);
+
+                       /* increase actualFrame */
+
+                       actualFrame += 2;
+
+                       /* if actualFrame > totalFrames the sequencer returns to frame 0,
+                        * beat 0. This must be the last operation. */
+
+                       if (actualFrame > totalFrames) {
+                               actualFrame = 0;
+                               actualBeat  = 0;
+                       }
+                       else
+                       if (actualFrame % framesPerBeat == 0 && actualFrame > 0) {
+                               actualBeat++;
+
+                               /* avoid tick and tock to overlap when a new bar has passed (which
+                                * is also a beat) */
+
+                               if (metronome && !tickPlay)
+                                       tockPlay = true;
+                       }
+
+                       sendMIDIsync();
+
+               } // if (running)
+
+               /* sum channels, CHANNEL_SAMPLE only */
+
+               pthread_mutex_lock(&mutex_chans);
+               for (unsigned k=0; k<channels.size; k++) {
+                       if (channels.at(k)->type == CHANNEL_SAMPLE)
+                               ((SampleChannel*)channels.at(k))->sum(j, running);
+               }
+               pthread_mutex_unlock(&mutex_chans);
+
+               /* metronome play */
+               /** FIXME - move this one after the peak meter calculation */
+
+               if (tockPlay) {
+                       outBuf[j]   += tock[tockTracker];
+                       outBuf[j+1] += tock[tockTracker];
+                       tockTracker++;
+                       if (tockTracker >= TICKSIZE-1) {
+                               tockPlay    = false;
+                               tockTracker = 0;
+                       }
+               }
+               if (tickPlay) {
+                       outBuf[j]   += tick[tickTracker];
+                       outBuf[j+1] += tick[tickTracker];
+                       tickTracker++;
+                       if (tickTracker >= TICKSIZE-1) {
+                               tickPlay    = false;
+                               tickTracker = 0;
+                       }
+               }
+       } // end loop J
+
+
+       /* final loop: sum virtual channels and process plugins. */
+
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned k=0; k<channels.size; k++)
+               channels.at(k)->process(outBuf);
+       pthread_mutex_unlock(&mutex_chans);
+
+       /* processing fxs master in & out, if any. */
+
+#ifdef WITH_VST
+       pthread_mutex_lock(&mutex_plugins);
+       G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT);
+       G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN);
+       pthread_mutex_unlock(&mutex_plugins);
+#endif
+
+       /* post processing master fx + peak calculation. */
+
+       for (unsigned j=0; j<bufferFrames; j+=2) {
+
+               /* merging vChanInToOut, if enabled */
+
+               if (inToOut) {
+                       outBuf[j]   += vChanInToOut[j];
+                       outBuf[j+1] += vChanInToOut[j+1];
+               }
+
+               outBuf[j]   *= outVol;
+               outBuf[j+1] *= outVol;
+
+               /* computes the peak for the left channel (so far). */
+
+               if (outBuf[j] > peakOut)
+                       peakOut = outBuf[j];
+
+               if (G_Conf.limitOutput) {
+                       if (outBuf[j] > 1.0f)
+                               outBuf[j] = 1.0f;
+                       else if (outBuf[j] < -1.0f)
+                               outBuf[j] = -1.0f;
+
+                       if (outBuf[j+1] > 1.0f)
+                               outBuf[j+1] = 1.0f;
+                       else if (outBuf[j+1] < -1.0f)
+                               outBuf[j+1] = -1.0f;
+               }
+       }
+
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::updateFrameBars() {
+
+       /* seconds ....... total time of play (in seconds) of the whole
+        *                 sequencer. 60 / bpm == how many seconds lasts one bpm
+        * totalFrames ... number of frames in the whole sequencer, x2 because
+        *                                                               it's stereo
+        * framesPerBar .. n. of frames within a bar
+        * framesPerBeat . n. of frames within a beat */
+
+       float seconds     = (60.0f / bpm) * beats;
+       totalFrames       = G_Conf.samplerate * seconds * 2;
+       framesPerBar      = totalFrames / bars;
+       framesPerBeat     = totalFrames / beats;
+       framesInSequencer = framesPerBeat * MAX_BEATS;
+
+       /* big troubles if frames are odd. */
+
+       if (totalFrames % 2 != 0)
+               totalFrames--;
+       if (framesPerBar % 2 != 0)
+               framesPerBar--;
+       if (framesPerBeat % 2 != 0)
+               framesPerBeat--;
+
+       updateQuanto();
+
+       /* realloc input virtual channel, if not NULL. TotalFrames is changed! */
+
+       if (vChanInput != NULL)
+               free(vChanInput);
+       vChanInput = (float*) malloc(totalFrames * sizeof(float));
+       if (!vChanInput)
+               gLog("[Mixer] vChanInput realloc error!\n");
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Mixer::close() {
+       running = false;
+       while (channels.size > 0)
+               deleteChannel(channels.at(0));
+       free(vChanInput);
+       free(vChanInToOut);
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool Mixer::isSilent() {
+       for (unsigned i=0; i<channels.size; i++)
+               if (channels.at(i)->status == STATUS_PLAY)
+                       return false;
+       return true;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::rewind() {
+
+       actualFrame = 0;
+       actualBeat  = 0;
+
+       if (running)
+               for (unsigned i=0; i<channels.size; i++)
+                       channels.at(i)->rewind();
+
+       sendMIDIrewind();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Mixer::updateQuanto() {
+
+       /* big troubles if frames are odd. */
+
+       if (quantize != 0)
+               quanto = framesPerBeat / quantize;
+       if (quanto % 2 != 0)
+               quanto++;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool Mixer::hasLogicalSamples() {
+       for (unsigned i=0; i<channels.size; i++)
+               if (channels.at(i)->type == CHANNEL_SAMPLE)
+                       if (((SampleChannel*)channels.at(i))->wave)
+                               if (((SampleChannel*)channels.at(i))->wave->isLogical)
+                                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool Mixer::hasEditedSamples() {
+       for (unsigned i=0; i<channels.size; i++)
+               if (channels.at(i)->type == CHANNEL_SAMPLE)
+                       if (((SampleChannel*)channels.at(i))->wave)
+                               if (((SampleChannel*)channels.at(i))->wave->isEdited)
+                                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool Mixer::mergeVirtualInput() {
+       if (vChanInput == NULL) {
+               gLog("[Mixer] virtual input channel not alloc'd\n");
+               return false;
+       }
+       else {
+#ifdef WITH_VST
+               G_PluginHost.processStackOffline(vChanInput, PluginHost::MASTER_IN, 0, totalFrames);
+#endif
+               int numFrames = totalFrames*sizeof(float);
+               memcpy(chanInput->wave->data, vChanInput, numFrames);
+               memset(vChanInput, 0, numFrames); // clear vchan
+               return true;
+       }
+}
diff --git a/src/core/mixer.h b/src/core/mixer.h
new file mode 100644 (file)
index 0000000..02eafd4
--- /dev/null
@@ -0,0 +1,209 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * mixer
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef MIXER_H
+#define MIXER_H
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "const.h"
+#include "kernelAudio.h"
+#include "../utils/utils.h"
+
+
+class Mixer {
+
+public:
+
+       Mixer();
+       ~Mixer();
+
+       void init();
+       int  close();
+
+       /* addChannel
+        * add a new channel without any wave inside of it. */
+
+       class Channel *addChannel(int type);
+
+       /* deleteChannel
+        * completely remove a channel from the stack. */
+
+       int deleteChannel(class Channel *ch);
+
+       /* masterPlay
+        * core method (callback) */
+
+       static int masterPlay(
+               void *out_buf, void *in_buf, unsigned n_frames,
+               double streamTime, RtAudioStreamStatus status, void *userData
+       );
+       int __masterPlay(void *out_buf, void *in_buf, unsigned n_frames);
+
+       /* updateFrameBars
+        * updates bpm, frames, beats and so on. */
+
+       void updateFrameBars();
+
+       /* isSilent
+        * is mixer silent? */
+
+       bool isSilent();
+
+       /* rewind
+        * rewind sequencer to sample 0. */
+
+       void rewind();
+
+       /* updateQuanto
+        * recomputes the quanto between two quantizations */
+
+       void updateQuanto();
+
+       /* hasLogicalSamples
+        * true if 1 or more samples are logical (memory only, such as takes) */
+
+       bool hasLogicalSamples();
+
+       /* hasEditedSamples
+        * true if 1 or more samples was edited via gEditor */
+
+       bool hasEditedSamples();
+
+       /* mergeVirtualInput
+        * memcpy the virtual channel input in the channel designed for input
+        * recording. Called by mixerHandler on stopInputRec() */
+
+       bool mergeVirtualInput();
+
+       /* getChannelByIndex
+        * return channel with given index 'i'. */
+
+       Channel *getChannelByIndex(int i);
+
+       inline Channel* getLastChannel() { return channels.at(channels.size-1); }
+
+
+       /* ---------------------------------------------------------------- */
+
+
+       enum {    // const - what to do when a fadeout ends
+               DO_STOP   = 0x01,
+               DO_MUTE   = 0x02,
+               DO_MUTE_I = 0x04
+       };
+
+       enum {    // const - fade types
+               FADEOUT = 0x01,
+               XFADE   = 0x02
+       };
+
+       gVector<class Channel*> channels;
+
+       bool   running;
+       bool   ready;
+       float *vChanInput;        // virtual channel for recording
+       float *vChanInToOut;      // virtual channel in->out bridge (hear what you're playin)
+       int    frameSize;
+       float  outVol;
+       float  inVol;
+       float  peakOut;
+       float  peakIn;
+       int    quanto;
+       char   quantize;
+       bool     metronome;
+       float  bpm;
+       int    bars;
+       int    beats;
+       int    waitRec;      // delayComp guard
+
+       bool docross;                      // crossfade guard
+       bool rewindWait;           // rewind guard, if quantized
+
+       int framesPerBar;      // frames in one bar
+       int framesPerBeat;     // frames in one beat
+       int framesInSequencer; // frames in the whole sequencer
+       int totalFrames;       // frames in the selected range (e.g. 4/4)
+       int actualFrame;
+       int actualBeat;
+
+#define TICKSIZE 38
+       static float tock[TICKSIZE];
+       static float tick[TICKSIZE];
+       int  tickTracker, tockTracker;
+       bool tickPlay, tockPlay; // 1 = play, 0 = stop
+
+       /* chanInput
+        * the active channel during a recording. NULL = no channels active */
+
+       class SampleChannel *chanInput;
+
+       /* inputTracker
+        * position of the sample in the input side (recording) */
+
+       int inputTracker;
+
+       /* inToOut
+        * copy, process and paste the input into the output, in order to
+        * obtain a "hear what you're playing" feature. */
+
+       bool inToOut;
+
+       pthread_mutex_t mutex_recs;
+       pthread_mutex_t mutex_chans;
+       pthread_mutex_t mutex_plugins;
+
+
+private:
+
+       int midiTCstep;      // part of MTC to send (0 to 7)
+       int midiTCrate;      // send MTC data every midiTCrate frames
+       int midiTCframes;
+       int midiTCseconds;
+       int midiTCminutes;
+       int midiTChours;
+
+       /* getNewIndex
+        * compute new index value for new channels */
+
+       int getNewIndex();
+
+       /* sendMIDIsync
+        * generate MIDI sync output data */
+
+       void sendMIDIsync();
+
+       /* sendMIDIrewind
+        * rewind timecode to beat 0 and also send a MTC full frame to cue
+        * the slave */
+
+       void sendMIDIrewind();
+};
+
+#endif
diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp
new file mode 100644 (file)
index 0000000..427808b
--- /dev/null
@@ -0,0 +1,230 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * mixerHandler
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#if defined(__linux__)
+       #include <jack/jack.h>
+       #include <jack/intclient.h>
+       #include <jack/transport.h>
+#endif
+
+#include "../utils/utils.h"
+#include "../utils/log.h"
+#include "../glue/glue.h"
+#include "mixerHandler.h"
+#include "kernelMidi.h"
+#include "mixer.h"
+#include "const.h"
+#include "init.h"
+#include "pluginHost.h"
+#include "plugin.h"
+#include "waveFx.h"
+#include "conf.h"
+#include "patch.h"
+#include "recorder.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "wave.h"
+
+
+extern Mixer             G_Mixer;
+extern Patch             G_Patch;
+extern Conf              G_Conf;
+
+#ifdef WITH_VST
+extern PluginHost G_PluginHost;
+#endif
+
+
+void mh_stopSequencer()
+{
+       G_Mixer.running = false;
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               G_Mixer.channels.at(i)->stopBySeq();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void mh_clear()
+{
+       G_Mixer.running = false;
+       while (G_Mixer.channels.size > 0)
+               G_Mixer.channels.del(0U);  // unsigned
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool mh_uniqueSolo(Channel *ch)
+{
+       int solos = 0;
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               Channel *ch = G_Mixer.channels.at(i);
+               if (ch->solo) solos++;
+               if (solos > 1) return false;
+       }
+       return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/** TODO - revision needed: mh should not call glue_addChannel */
+
+void mh_loadPatch(bool isProject, const char *projPath)
+{
+       G_Mixer.init();
+       G_Mixer.ready = false;   // put it in wait mode
+
+       int numChans = G_Patch.getNumChans();
+       for (int i=0; i<numChans; i++) {
+
+               Channel *ch = glue_addChannel(G_Patch.getColumn(i), G_Patch.getType(i));
+
+               char smpPath[PATH_MAX];
+               sprintf(smpPath, "%s%s%s", gDirname(projPath).c_str(), gGetSlash().c_str(), G_Patch.getSamplePath(i).c_str());
+
+               ch->loadByPatch(smpPath, i);
+       }
+
+       G_Mixer.outVol     = G_Patch.getOutVol();
+       G_Mixer.inVol      = G_Patch.getInVol();
+       G_Mixer.bpm        = G_Patch.getBpm();
+       G_Mixer.bars       = G_Patch.getBars();
+       G_Mixer.beats      = G_Patch.getBeats();
+       G_Mixer.quantize   = G_Patch.getQuantize();
+       G_Mixer.metronome  = G_Patch.getMetronome();
+       G_Patch.lastTakeId = G_Patch.getLastTakeId();
+       G_Patch.samplerate = G_Patch.getSamplerate();
+
+       /* rewind and update frames in Mixer (it's vital) */
+
+       G_Mixer.rewind();
+       G_Mixer.updateFrameBars();
+       G_Mixer.ready = true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void mh_rewindSequencer()
+{
+       if (G_Mixer.quantize > 0 && G_Mixer.running)   // quantize rewind
+               G_Mixer.rewindWait = true;
+       else
+               G_Mixer.rewind();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+SampleChannel *mh_startInputRec()
+{
+       /* search for the next available channel */
+
+       SampleChannel *chan = NULL;
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
+                       if (((SampleChannel*) G_Mixer.channels.at(i))->canInputRec()) {
+                       chan = (SampleChannel*) G_Mixer.channels.at(i);
+                       break;
+               }
+       }
+
+       /* no chans available? */
+
+       if (chan == NULL)
+               return NULL;
+
+       Wave *w = new Wave();
+       if (!w->allocEmpty(G_Mixer.totalFrames))
+               return NULL;
+
+       /* increase lastTakeId until the sample name TAKE-[n] is unique */
+
+       char name[32];
+       sprintf(name, "TAKE-%d", G_Patch.lastTakeId);
+       while (!mh_uniqueSamplename(chan, name)) {
+               G_Patch.lastTakeId++;
+               sprintf(name, "TAKE-%d", G_Patch.lastTakeId);
+       }
+
+       chan->allocEmpty(G_Mixer.totalFrames, G_Patch.lastTakeId);
+       G_Mixer.chanInput = chan;
+
+       /* start to write from the actualFrame, not the beginning */
+       /** FIXME: move this before wave allocation*/
+
+       G_Mixer.inputTracker = G_Mixer.actualFrame;
+
+       gLog(
+               "[mh] start input recs using chan %d with size %d, frame=%d\n",
+               chan->index, G_Mixer.totalFrames, G_Mixer.inputTracker
+       );
+
+       return chan;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+SampleChannel *mh_stopInputRec()
+{
+       gLog("[mh] stop input recs\n");
+       G_Mixer.mergeVirtualInput();
+       SampleChannel *ch = G_Mixer.chanInput;
+       G_Mixer.chanInput = NULL;
+       G_Mixer.waitRec   = 0;                                  // if delay compensation is in use
+       return ch;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool mh_uniqueSamplename(SampleChannel *ch, const char *name)
+{
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               if (ch != G_Mixer.channels.at(i)) {
+                       if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
+                               SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i);
+                               if (other->wave != NULL)
+                                       if (!strcmp(name, other->wave->name.c_str()))
+                                               return false;
+                       }
+               }
+       }
+       return true;
+}
diff --git a/src/core/mixerHandler.h b/src/core/mixerHandler.h
new file mode 100644 (file)
index 0000000..f842004
--- /dev/null
@@ -0,0 +1,76 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * mixerHandler
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef MIXERHANDLER_H
+#define MIXERHANDLER_H
+
+
+#include "recorder.h"
+
+
+/* stopSequencer
+ * stop the sequencer, with special case if samplesStopOnSeqHalt is
+ * true. */
+
+void mh_stopSequencer();
+
+void mh_rewindSequencer();
+
+/* clear
+ * stop everything and clear all channels. */
+void mh_clear();
+
+/* uniqueSolo
+ * true if ch is the only solo'd channel in mixer. */
+
+bool mh_uniqueSolo(class Channel *ch);
+
+/* loadPatch
+ * load a path or a project (if isProject) into Mixer. If isProject, path
+ * must contain the address of the project folder. */
+
+void mh_loadPatch(bool isProject, const char *projPath=0);
+
+/* startInputRec - record from line in
+ * creates a new empty wave in the first available channels and returns
+ * the chan number chosen, otherwise -1 if there are no more empty
+ * channels available. */
+
+SampleChannel *mh_startInputRec();
+
+SampleChannel *mh_stopInputRec();
+
+/* uniqueSamplename
+ * return true if samplename 'n' is unique. Requires SampleChannel *ch
+ * in order to skip check against itself. */
+
+bool mh_uniqueSamplename(class SampleChannel *ch, const char *name);
+
+#endif
diff --git a/src/core/patch.cpp b/src/core/patch.cpp
new file mode 100644 (file)
index 0000000..3613070
--- /dev/null
@@ -0,0 +1,739 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * patch
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#include "../utils/log.h"
+#include "../utils/utils.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "patch.h"
+#include "init.h"
+#include "recorder.h"
+#include "conf.h"
+#include "pluginHost.h"
+#include "wave.h"
+#include "mixer.h"
+#include "channel.h"
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+#ifdef WITH_VST
+extern PluginHost    G_PluginHost;
+#endif
+extern gdMainWindow *mainWin;
+
+
+int Patch::open(const char *file)
+{
+       fp = fopen(file, "r");
+       if (fp == NULL)
+               return PATCH_UNREADABLE;
+
+       if (getValue("header") != "GIADAPTC")
+               return PATCH_INVALID;
+
+       version = atof(getValue("versionf").c_str());
+       gLog("[patch] open patch version %f\n", version);
+
+       return PATCH_OPEN_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Patch::setDefault()
+{
+       name[0]    = '\0';
+  lastTakeId = 0;
+  samplerate = DEFAULT_SAMPLERATE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::close()
+{
+       return fclose(fp);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Patch::getName()
+{
+       std::string out = getValue("patchname");
+       strncpy(name, out.c_str(), MAX_PATCHNAME_LEN);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string Patch::getSamplePath(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "samplepath%d", c);
+       return getValue(tmp);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getPitch(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanPitch%d", c);
+       float out = atof(getValue(tmp).c_str());
+       if (out > 2.0f || out < 0.1f)
+               return 1.0f;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getNumChans()
+{
+       if (version == 0.0)      // backward compatibility with version < 0.6.1
+               return 32;
+       return atoi(getValue("channels").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getNumColumns()
+{
+       return atoi(getValue("columns").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getColumn(int c)
+{
+       if (version == 0.0)      // backward compatibility with version < 0.6.1
+               return 0;
+       char tmp[16];
+       sprintf(tmp, "chanColumn%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getIndex(int c)
+{
+       if (version == 0.0)      // backward compatibility with version < 0.6.1
+               return c;
+
+       char tmp[16];
+       sprintf(tmp, "chanIndex%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getVol(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanvol%d", c);
+       float out = atof(getValue(tmp).c_str());
+       if (out > 1.0f || out < 0.0f)
+               return DEFAULT_VOL;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getMode(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanmode%d", c);
+       int out = atoi(getValue(tmp).c_str());
+       if (out & (LOOP_ANY | SINGLE_ANY))
+               return out;
+       return DEFAULT_CHANMODE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getMute(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanMute%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getMute_s(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanMute_s%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getSolo(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanSolo%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getType(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanType%d", c);
+       int out = atoi(getValue(tmp).c_str());
+       if (out == 0)
+               return CHANNEL_SAMPLE;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getBegin(int c)
+{
+       char tmp[16];
+       if (version < 0.73f)
+               sprintf(tmp, "chanstart%d", c);
+       else
+               sprintf(tmp, "chanBegin%d", c);
+       int out = atoi(getValue(tmp).c_str());
+       if (out < 0)
+               return 0;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getEnd(int c, unsigned size)
+{
+       char tmp[16];
+       sprintf(tmp, "chanend%d", c);
+
+       /* if chanEnd doesn't exist, it returns an atoi(empty string) == 0.
+        * good in theory, a disaster in practice. */
+
+       std::string val = getValue(tmp);
+       if (val == "")
+               return size;
+
+       unsigned out = atoi(val.c_str());
+       if (out <= 0 || out > size)
+               return size;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getBoost(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanBoost%d", c);
+       float out = atof(getValue(tmp).c_str());
+       if (out < 1.0f)
+               return DEFAULT_BOOST;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getPanLeft(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanPanLeft%d", c);
+       std::string val = getValue(tmp);
+       if (val == "")
+               return 1.0f;
+
+       float out = atof(val.c_str());
+       if (out < 0.0f || out > 1.0f)
+               return 1.0f;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getKey(int c)
+{
+       if (version == 0.0)      // backward compatibility with version < 0.6.1
+               return 0;
+       char tmp[16];
+       sprintf(tmp, "chanKey%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getPanRight(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanPanRight%d", c);
+       std::string val = getValue(tmp);
+       if (val == "")
+               return 1.0f;
+
+       float out = atof(val.c_str());
+       if (out < 0.0f || out > 1.0f)
+               return 1.0f;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool Patch::getRecActive(int c)
+{
+       char tmp[16];
+       sprintf(tmp, "chanRecActive%d", c);
+       return atoi(getValue(tmp).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getOutVol()
+{
+       return atof(getValue("outVol").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getInVol()
+{
+       return atof(getValue("inVol").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float Patch::getBpm()
+{
+       float out = atof(getValue("bpm").c_str());
+       if (out < 20.0f || out > 999.0f)
+               return DEFAULT_BPM;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getBars()
+{
+       int out = atoi(getValue("bars").c_str());
+       if (out <= 0 || out > 32)
+               return DEFAULT_BARS;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getBeats()
+{
+       int out = atoi(getValue("beats").c_str());
+       if (out <= 0 || out > 32)
+               return DEFAULT_BEATS;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getQuantize()
+{
+       int out = atoi(getValue("quantize").c_str());
+       if (out < 0 || out > 8)
+               return DEFAULT_QUANTIZE;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool Patch::getMetronome()
+{
+       return atoi(getValue("metronome").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getLastTakeId()
+{
+       return atoi(getValue("lastTakeId").c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::getSamplerate()
+{
+       int out = atoi(getValue("samplerate").c_str());
+       if (out <= 0)
+               return DEFAULT_SAMPLERATE;
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+uint32_t Patch::getMidiValue(int i, const char *c)
+{
+       char tmp[32];
+       sprintf(tmp, "chanMidi%s%d", c, i);
+       return strtoul(getValue(tmp).c_str(), NULL, 10);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::readRecs()
+{
+       gLog("[patch] Reading recs...\n");
+
+       unsigned numrecs = atoi(getValue("numrecs").c_str());
+
+       for (unsigned i=0; i<numrecs; i++) {
+               int frame, recPerFrame;
+
+               /* parsing 'dddddd d': [framenumber] [num. recs for that frame]  */
+
+               char tmpbuf[16];
+               sprintf(tmpbuf, "recframe%d", i);
+               sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame);
+
+//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
+
+               for (int k=0; k<recPerFrame; k++) {
+                       int      chan = 0;
+                       int      type = 0;
+                       float    fValue = 0.0f;
+                       int      iValue_fix = 0;
+                       uint32_t iValue = 0;
+
+                       /* reading info for each frame: %d|%d */
+
+                       char tmpbuf[16];
+                       sprintf(tmpbuf, "f%da%d", i, k);
+
+                       if (version < 0.61f)    // no float and int values
+                               sscanf(getValue(tmpbuf).c_str(), "%d|%d", &chan, &type);
+                       else
+                               if (version < 0.83f)  // iValues were stored as signed int (wrong)
+                                       sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%d", &chan, &type, &fValue, &iValue_fix);
+                               else
+                                       sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%u", &chan, &type, &fValue, &iValue);
+
+//gLog("  loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
+
+                       Channel *ch = G_Mixer.getChannelByIndex(chan);
+                       if (ch)
+                               if (ch->status & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) {
+                                       if (version < 0.83f)
+                                               recorder::rec(ch->index, type, frame, iValue_fix, fValue);
+                                       else
+                                               recorder::rec(ch->index, type, frame, iValue, fValue);
+                               }
+               }
+       }
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+int Patch::readPlugins()
+{
+       gLog("[patch] Reading plugins...\n");
+
+       int globalOut = 1;
+
+       /* master plugins */
+
+       globalOut &= readMasterPlugins(PluginHost::MASTER_IN);
+       globalOut &= readMasterPlugins(PluginHost::MASTER_OUT);
+
+       /* channel plugins */
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               Channel *ch = G_Mixer.channels.at(i);
+
+               char tmp[MAX_LINE_LEN];
+               sprintf(tmp, "chan%dPlugins", ch->index);
+               int np = atoi(getValue(tmp).c_str());
+
+               for (int j=0; j<np; j++) {
+                       sprintf(tmp, "chan%d_p%dpathfile", ch->index, j);
+                       int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), PluginHost::CHANNEL, ch);
+                       if (out != 0) {
+                               sprintf(tmp, "chan%d_p%dnumParams", ch->index, j);
+                               int nparam = atoi(getValue(tmp).c_str());
+                               Plugin *pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch);
+                               sprintf(tmp, "chan%d_p%dbypass", ch->index, j);
+                               pPlugin->bypass = atoi(getValue(tmp).c_str());
+                               for (int k=0; k<nparam; k++) {
+                                       sprintf(tmp, "chan%d_p%dparam%dvalue", ch->index, j, k);
+                                       float pval = atof(getValue(tmp).c_str());
+                                       pPlugin->setParam(k, pval);
+                               }
+                       }
+                       globalOut &= out;
+               }
+       }
+       return globalOut;
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Patch::write(const char *file, const char *name, bool project)
+{
+       fp = fopen(file, "w");
+       if (fp == NULL)
+               return 0;
+
+       fprintf(fp, "# --- Giada patch file --- \n");
+       fprintf(fp, "header=GIADAPTC\n");
+       fprintf(fp, "version=%s\n",    VERSIONE);
+       fprintf(fp, "versionf=%f\n",   VERSIONE_FLOAT);
+       fprintf(fp, "patchname=%s\n",  name);
+       fprintf(fp, "bpm=%f\n",        G_Mixer.bpm);
+       fprintf(fp, "bars=%d\n",       G_Mixer.bars);
+       fprintf(fp, "beats=%d\n",      G_Mixer.beats);
+       fprintf(fp, "quantize=%d\n",   G_Mixer.quantize);
+       fprintf(fp, "outVol=%f\n",     G_Mixer.outVol);
+       fprintf(fp, "inVol=%f\n",      G_Mixer.inVol);
+       fprintf(fp, "metronome=%d\n",  G_Mixer.metronome);
+       fprintf(fp, "lastTakeId=%d\n", lastTakeId);
+       fprintf(fp, "samplerate=%d\n", G_Conf.samplerate);      // original samplerate when the patch was saved
+       fprintf(fp, "channels=%d\n",   G_Mixer.channels.size);
+       fprintf(fp, "columns=%d\n",    mainWin->keyboard->getTotalColumns());
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               fprintf(fp, "# --- channel %d --- \n", i);
+               G_Mixer.channels.at(i)->writePatch(fp, i, project);
+       }
+
+       /* writing recs. Warning: channel index is not mixer.channels.at(chan),
+        * but mixer.channels.at(chan)->index! */
+
+       fprintf(fp, "# --- actions --- \n");
+       fprintf(fp, "numrecs=%d\n", recorder::global.size);
+       for (unsigned i=0; i<recorder::global.size; i++) {
+               fprintf(fp, "recframe%d=%d %d\n", i, recorder::frames.at(i), recorder::global.at(i).size);
+               for (unsigned k=0; k<recorder::global.at(i).size; k++) {
+                       fprintf(fp, "f%da%d=%d|%d|%f|%u\n",
+                               i, k,
+                               recorder::global.at(i).at(k)->chan,
+                               recorder::global.at(i).at(k)->type,
+                               recorder::global.at(i).at(k)->fValue,
+                               recorder::global.at(i).at(k)->iValue);
+               }
+       }
+
+#ifdef WITH_VST
+
+       /* writing master VST parameters */
+
+       writeMasterPlugins(PluginHost::MASTER_IN);
+       writeMasterPlugins(PluginHost::MASTER_OUT);
+
+       /* writing VST parameters, channels. chan%d is mixer::channels.at(%d)->index,
+        * not mixer::chanels.at(%d)! */
+
+       int numPlugs;
+       int numParams;
+       Plugin *pPlugin;
+
+       fprintf(fp, "# --- VST / channels --- \n");
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               Channel *ch = G_Mixer.channels.at(i);
+               numPlugs    = G_PluginHost.countPlugins(PluginHost::CHANNEL, ch);
+               fprintf(fp, "chan%dPlugins=%d\n", ch->index, numPlugs);
+
+               for (int j=0; j<numPlugs; j++) {
+                       pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch);
+                       if (!pPlugin->status) {
+                               gLog("[patch] Plugin %d is in a bad status, skip writing params\n", i);
+                               continue;
+                       }
+                       fprintf(fp, "chan%d_p%dpathfile=%s\n", ch->index, j, pPlugin->pathfile);
+                       fprintf(fp, "chan%d_p%dbypass=%d\n",   ch->index, j, pPlugin->bypass);
+                       numParams = pPlugin->getNumParams();
+                       fprintf(fp, "chan%d_p%dnumParams=%d\n", ch->index, j, numParams);
+
+                       for (int k=0; k<numParams; k++)
+                               fprintf(fp, "chan%d_p%dparam%dvalue=%f\n", ch->index, j, k, pPlugin->getParam(k));
+               }
+       }
+
+#endif
+
+       fclose(fp);
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef WITH_VST
+
+int Patch::readMasterPlugins(int type)
+{
+       int  nmp;
+       char chr;
+       int  res = 1;
+
+       if (type == PluginHost::MASTER_IN) {
+               chr = 'I';
+               nmp = atoi(getValue("masterIPlugins").c_str());
+       }
+       else {
+               chr = 'O';
+               nmp = atoi(getValue("masterOPlugins").c_str());
+       }
+
+       for (int i=0; i<nmp; i++) {
+               char tmp[MAX_LINE_LEN];
+               sprintf(tmp, "master%c_p%dpathfile", chr, i);
+               int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), type);
+               if (out != 0) {
+                       Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
+                       sprintf(tmp, "master%c_p%dbypass", chr, i);
+                       pPlugin->bypass = atoi(getValue(tmp).c_str());
+                       sprintf(tmp, "master%c_p%dnumParams", chr, i);
+                       int nparam = atoi(getValue(tmp).c_str());
+                       for (int j=0; j<nparam; j++) {
+                               sprintf(tmp, "master%c_p%dparam%dvalue", chr, i, j);
+                               float pval = atof(getValue(tmp).c_str());
+                               pPlugin->setParam(j, pval);
+                       }
+               }
+               res &= out;
+       }
+
+       return res;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Patch::writeMasterPlugins(int type)
+{
+       char chr;
+
+       if (type == PluginHost::MASTER_IN) {
+               fprintf(fp, "# --- VST / master in --- \n");
+               chr = 'I';
+       }
+       else {
+               fprintf(fp, "# --- VST / master out --- \n");
+               chr = 'O';
+       }
+
+       int nmp = G_PluginHost.countPlugins(type);
+       fprintf(fp, "master%cPlugins=%d\n", chr, nmp);
+
+       for (int i=0; i<nmp; i++) {
+
+               Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
+               if (!pPlugin->status) {
+                       gLog("[patch] Plugin %d is in a bad status, skip writing params\n", i);
+                       continue;
+               }
+
+               fprintf(fp, "master%c_p%dpathfile=%s\n", chr, i, pPlugin->pathfile);
+               fprintf(fp, "master%c_p%dbypass=%d\n", chr, i, pPlugin->bypass);
+               int numParams = pPlugin->getNumParams();
+               fprintf(fp, "master%c_p%dnumParams=%d\n", chr, i, numParams);
+
+               for (int j=0; j<numParams; j++)
+                       fprintf(fp, "master%c_p%dparam%dvalue=%f\n", chr, i, j, pPlugin->getParam(j));
+       }
+}
+
+#endif
diff --git a/src/core/patch.h b/src/core/patch.h
new file mode 100644 (file)
index 0000000..e431b85
--- /dev/null
@@ -0,0 +1,95 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * patch
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __PATCH_H__
+#define __PATCH_H__
+
+#include <stdio.h>
+#include <string>
+#include <stdint.h>
+#include "dataStorage.h"
+#include "const.h"
+
+
+class Patch : public DataStorage {
+
+private:
+       int  readMasterPlugins(int type);
+       void writeMasterPlugins(int type);
+
+public:
+
+       char  name[MAX_PATCHNAME_LEN];
+       float version;
+       int   lastTakeId;
+       int   samplerate;
+
+       int         open(const char *file);
+       void        setDefault();
+       int         close();
+
+       void                            getName       ();
+       int         getNumChans   ();
+       int                                     getNumColumns ();
+       std::string getSamplePath (int i);
+       float       getVol        (int i);
+       int         getMode       (int i);
+       int         getMute       (int i);
+       int         getMute_s     (int i);
+       int         getSolo       (int i);
+       int         getBegin      (int i);
+       int         getEnd        (int i, unsigned sampleSize);
+       float       getBoost      (int i);
+       float       getPanLeft    (int i);
+       float       getPanRight   (int i);
+       float       getPitch      (int i);
+       bool        getRecActive  (int i);
+       int         getColumn     (int i);
+       int         getIndex      (int i);
+       int         getType       (int i);
+       int         getKey        (int i);
+       uint32_t    getMidiValue  (int i, const char *c);
+       float       getOutVol     ();
+       float       getInVol      ();
+       float       getBpm        ();
+       int         getBars       ();
+       int         getBeats      ();
+       int         getQuantize   ();
+       bool        getMetronome  ();
+       int         getLastTakeId ();
+       int         getSamplerate ();
+
+       int         write(const char *file, const char *name, bool isProject);
+       int         readRecs();
+#ifdef WITH_VST
+       int         readPlugins();
+#endif
+};
+
+#endif
diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp
new file mode 100644 (file)
index 0000000..d54c7df
--- /dev/null
@@ -0,0 +1,520 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+
+
+#include "../utils/log.h"
+#include "plugin.h"
+
+
+int Plugin::id_generator = 0;
+
+
+/* ------------------------------------------------------------------ */
+
+
+Plugin::Plugin()
+       : module    (NULL),
+         entryPoint(NULL),
+         plugin    (NULL),
+         id        (id_generator++),
+         program   (-1),
+         bypass    (false),
+         suspended (false)
+{}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Plugin::~Plugin() {
+       unload();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::unload() {
+
+       if (module == NULL)
+               return 1;
+
+#if defined(_WIN32)
+
+       FreeLibrary((HMODULE)module); // FIXME - error checking
+       return 1;
+
+#elif defined(__linux__)
+
+       return dlclose(module) == 0 ? 1 : 0;
+
+#elif defined(__APPLE__)
+
+       /* we must unload bundles but because bundles may be in use for other
+       plug-in types it is important (and mandatory on certain plug-ins,
+       e.g. Korg) to do a check on the retain count. */
+
+       CFIndex retainCount = CFGetRetainCount(module);
+
+       if (retainCount == 1) {
+               gLog("[plugin] retainCount == 1, can unload dlyb\n");
+               CFBundleUnloadExecutable(module);
+               CFRelease(module);
+       }
+       else
+               gLog("[plugin] retainCount > 1 (%d), leave dlyb alone\n", (int) retainCount);
+
+       return 1;
+
+#endif
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::load(const char *fname) {
+
+       strcpy(pathfile, fname);
+
+#if defined(_WIN32)
+
+       module = LoadLibrary(pathfile);
+
+#elif defined(__linux__)
+
+       module = dlopen(pathfile, RTLD_LAZY);
+
+#elif defined(__APPLE__)
+
+  /* creates the path to the bundle. In OSX vsts are stored inside the
+   * so-called bundles, just a directory with '.vst' extension. Finally
+   * we open the bundle with CFBundleCreate. */
+
+  CFStringRef pathStr   = CFStringCreateWithCString(NULL, pathfile, kCFStringEncodingASCII);
+  CFURLRef    bundleUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,   pathStr, kCFURLPOSIXPathStyle, true);
+  if(bundleUrl == NULL) {
+    gLog("[plugin] unable to create URL reference for plugin\n");
+    status = 0;
+    return 0;
+  }
+  module = CFBundleCreate(kCFAllocatorDefault, bundleUrl);
+
+#endif
+
+       if (module) {
+
+       /* release (free) any old string */
+
+#ifdef __APPLE__
+               CFRelease(pathStr);
+               CFRelease(bundleUrl);
+#endif
+               //strcpy(pathfile, fname); ???????????
+               status = 1;
+               return 1;
+       }
+       else {
+
+#if defined(_WIN32)
+
+               gLog("[plugin] unable to load %s, error: %d\n", fname, (int) GetLastError());
+
+#elif defined(__linux__)
+
+               gLog("[plugin] unable to load %s, error: %s\n", fname, dlerror());
+
+#elif defined(__APPLE__)
+
+    gLog("[plugin] unable to create bundle reference\n");
+    CFRelease(pathStr);
+    CFRelease(bundleUrl);
+
+#endif
+               status = 0;
+               return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::init(VstIntPtr VSTCALLBACK (*HostCallback) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt)) {
+
+#if defined(_WIN32)
+
+       entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "VSTPluginMain");
+       if (!entryPoint)
+               entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "main");
+
+#elif defined(__linux__)
+
+       /* bad stuff here: main() is a function pointer, dlsym(module, "main")
+        * returns a pointer to an object (void*) which should be casted to
+        * a pointer to function (main(), precisely). Unfortunately the standard
+        * forbids the conversion from void* to function pointer. So we do a raw
+        * mem copy from tmp to entryPoint. */
+
+       void *tmp;
+       tmp = dlsym(module, "VSTPluginMain");
+       if (!tmp)
+               tmp = dlsym(module, "main");
+       memcpy(&entryPoint, &tmp, sizeof(tmp));
+
+#elif defined(__APPLE__)
+
+       /* same also for Unix/OSX. */
+
+       void *tmp = NULL;
+       tmp = CFBundleGetFunctionPointerForName(module, CFSTR("VSTPluginMain"));
+
+       if (!tmp) {
+               gLog("[plugin] entryPoint 'VSTPluginMain' not found\n");
+               tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main_macho"));  // VST SDK < 2.4
+       }
+       if (!tmp) {
+               gLog("[plugin] entryPoint 'main_macho' not found\n");
+               tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main"));
+       }
+       if (tmp)
+               memcpy(&entryPoint, &tmp, sizeof(tmp));
+       else
+               gLog("[plugin] entryPoint 'main' not found\n");
+
+#endif
+
+       /* if entry point is found, add to plugin a pointer to hostCallback. Or
+        * in other words bind the callback to the plugin. */
+
+       if (entryPoint) {
+               gLog("[plugin] entryPoint found\n");
+               plugin = entryPoint(HostCallback);
+               if (!plugin) {
+                       gLog("[plugin] failed to create effect instance!\n");
+                       return 0;
+               }
+       }
+       else {
+               gLog("[plugin] entryPoint not found, unable to proceed\n");
+               return 0;
+       }
+
+
+       /* check the magicNumber */
+       /** WARNING: on Windows one can load any DLL! Why!?! */
+
+  if(plugin->magic == kEffectMagic) {
+               gLog("[plugin] magic number OK\n");
+               return 1;
+       }
+       else {
+    gLog("[plugin] magic number is bad\n");
+    return 0;
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::setup(int samplerate, int frames) {
+
+  /* init plugin through the dispatcher with some basic infos */
+
+  plugin->dispatcher(plugin, effOpen, 0, 0, 0, 0);
+       plugin->dispatcher(plugin, effSetSampleRate, 0, 0, 0, samplerate);
+       plugin->dispatcher(plugin, effSetBlockSize, 0, frames, 0, 0);
+
+       /* check SDK compatibility */
+
+       if (getSDKVersion() != kVstVersion)
+               gLog("[plugin] warning: different VST version (host: %d, plugin: %d)\n", kVstVersion, getSDKVersion());
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+AEffect *Plugin::getPlugin() {
+       return plugin;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getId() { return id; }
+
+
+/* ------------------------------------------------------------------ */
+
+int Plugin::getSDKVersion() {
+       return plugin->dispatcher(plugin, effGetVstVersion, 0, 0, 0, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getName(char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetEffectName, 0, 0, tmp, 0);
+       tmp[kVstMaxEffectNameLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxEffectNameLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getVendor(char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetVendorString, 0, 0, tmp, 0);
+       tmp[kVstMaxVendorStrLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxVendorStrLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getProduct(char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetProductString, 0, 0, tmp, 0);
+       tmp[kVstMaxProductStrLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxProductStrLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getNumPrograms() { return plugin->numPrograms; }
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::setProgram(int index) {
+       plugin->dispatcher(plugin, effBeginSetProgram, 0, 0, 0, 0);
+       plugin->dispatcher(plugin, effSetProgram, 0, index, 0, 0);
+       gLog("[plugin] program changed, index %d\n", index);
+       program = index;
+       return plugin->dispatcher(plugin, effEndSetProgram, 0, 0, 0, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getNumParams() { return plugin->numParams; }
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getNumInputs() { return plugin->numInputs; }
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getNumOutputs() {  return plugin->numOutputs; }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getProgramName(int index, char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetProgramNameIndexed, index, 0, tmp, 0);
+       tmp[kVstMaxProgNameLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxProgNameLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getParamName(int index, char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetParamName, index, 0, tmp, 0);
+       tmp[kVstMaxParamStrLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxParamStrLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getParamLabel(int index, char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetParamLabel, index, 0, tmp, 0);
+       tmp[kVstMaxParamStrLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxParamStrLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getParamDisplay(int index, char *out) {
+       char tmp[128] = "\0";
+       plugin->dispatcher(plugin, effGetParamDisplay, index, 0, tmp, 0);
+       tmp[kVstMaxParamStrLen-1] = '\0';
+       strncpy(out, tmp, kVstMaxParamStrLen);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+float Plugin::getParam(int index) {
+       return plugin->getParameter(plugin, index);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::setParam(int index, float value) {
+       plugin->setParameter(plugin, index, value);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool Plugin::hasGui() {
+       return plugin->flags & effFlagsHasEditor;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::openGui(void *w) {
+       long val = 0;
+#ifdef __linux__
+  val = (long) w;
+#endif
+       plugin->dispatcher(plugin, effEditOpen, 0, val, w, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::closeGui() {
+       plugin->dispatcher(plugin, effEditClose, 0, 0, 0, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getGuiWidth() {
+       ERect *pErect = NULL;
+       plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0);
+       return pErect->top + pErect->right;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Plugin::getGuiHeight() {
+       ERect *pErect = NULL;
+       plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0);
+       return pErect->top + pErect->bottom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::idle() {
+       plugin->dispatcher(plugin, effEditIdle, 0, 0, NULL, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::processAudio(float **in, float **out, long frames) {
+       plugin->processReplacing(plugin, in, out, frames);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::processEvents(VstEvents *events) {
+       plugin->dispatcher(plugin, effProcessEvents, 0, 0, events, 0.0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::resume() {
+       plugin->dispatcher(plugin, effMainsChanged, 0, 1, 0, 0);
+       suspended = false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::suspend() {
+       plugin->dispatcher(plugin, effMainsChanged, 0, 0, 0, 0);
+       suspended = true;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::close() {
+       plugin->dispatcher(plugin, effClose, 0, 0, 0, 0);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Plugin::getRect(ERect **out) {
+       plugin->dispatcher(plugin, effEditGetRect, 0, 0, out, 0);
+}
+
+
+#endif
diff --git a/src/core/plugin.h b/src/core/plugin.h
new file mode 100644 (file)
index 0000000..b03c343
--- /dev/null
@@ -0,0 +1,168 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * plugin
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifdef WITH_VST
+
+#ifndef __PLUGIN_H
+#define __PLUGIN_H
+
+#include <cstdio>
+
+/* before including aeffetx(x).h we must define __cdecl, otherwise VST
+ * headers can't be compiled correctly. In windows __cdecl is already
+ * defined. */
+
+#ifdef __GNUC__
+       #ifndef _WIN32
+               #define __cdecl
+       #endif
+#endif
+
+#include "../deps/vst/aeffectx.h"
+
+#if defined(_WIN32)
+       #include <windows.h>
+#elif defined(__linux__)
+       #include <dlfcn.h>
+       #include <X11/Xlib.h>
+#elif defined(__APPLE__)
+       #include <CoreFoundation/CFBundle.h>
+#endif
+
+#include <limits.h>  // PATH_MAX
+
+
+// Plugin's entry point
+typedef AEffect* (*vstPluginFuncPtr)(audioMasterCallback host);
+
+
+class Plugin {
+
+private:
+
+#if defined(_WIN32) || defined(__linux__)
+       void             *module;     // dll, so, ...
+#elif defined(__APPLE__)
+       CFBundleRef       module;                       // OSX bundle
+#endif
+
+       vstPluginFuncPtr  entryPoint; // VST entry point
+       AEffect          *plugin;     // real plugin
+
+       /* each plugin has an unique ID */
+
+       static int id_generator;
+       int        id;
+
+       /* program
+        * selected program. -1 if no program available */
+
+       int program;
+
+       /* unload
+        * free plugin from memory. Calls dlclose and similars. */
+
+       int unload();
+
+public:
+       Plugin();
+       ~Plugin();
+
+       int  load(const char *fname);
+       int  init(VstIntPtr VSTCALLBACK (*HostCallback)(AEffect*, VstInt32, VstInt32, VstIntPtr, void*, float));
+       int  setup(int samplerate, int frames);
+
+       AEffect *getPlugin();
+
+       /* get[Item].
+        * Wrappers called by host when it wants info from the plugin. */
+
+       int   getId();
+       int   getSDKVersion();
+       void  getName   (char *out);
+       void  getVendor (char *out);
+       void  getProduct(char *out);
+       int   getNumPrograms();        // list all programs
+       int   setProgram(int index);   // load a program
+       int   getNumParams();
+       int   getNumInputs();
+       int   getNumOutputs();
+       void  getProgramName(int index, char *out);  // program = preset
+       void  getParamName(int index, char *out);
+       void  getParamLabel(int index, char *out);   // parameter's value(0, -39, ...)
+       void  getParamDisplay(int index, char *out); // parameter's unit measurement (dB, Pan, ...)
+       float getParam(int index);
+       void  getRect(ERect **out);
+       void  setParam(int index, float value);
+
+       bool  hasGui();
+       void  openGui(void *w);
+       void  closeGui();
+       int   getGuiWidth();
+       int   getGuiHeight();
+       void  idle();
+
+       void  processAudio (float **in, float **out, long frames);
+       void  processEvents(VstEvents *events);
+       void  resume();
+       void  suspend();
+       void  close();
+
+       inline int getProgram() { return program; }
+
+       /* there's a specific opcode for the bypass, but we don't trust the
+        * plugin's developers. */
+
+       bool bypass;
+
+       /* the status of the plugin:
+        * 1: ok
+        * 0: missing (file not found) */
+
+       int status;
+
+       /* suspended
+        * true after suspend(), false after resume(). A suspended plugin isn't
+        * processed by pluginHost. */
+
+       bool suspended;
+
+       /* pathfile
+        * full filename path */
+
+       char pathfile[PATH_MAX];
+
+       /* window
+        * plugin must know its window in case of a resize via opcode */
+
+       class gWindow *window;
+};
+
+#endif
+
+#endif // #ifdef WITH_VST
diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp
new file mode 100644 (file)
index 0000000..6202050
--- /dev/null
@@ -0,0 +1,679 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * pluginHost
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+
+
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../utils/log.h"
+#include "pluginHost.h"
+#include "conf.h"
+#include "const.h"
+#include "mixer.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "midiChannel.h"
+#include "kernelMidi.h"
+
+
+extern Conf          G_Conf;
+extern Mixer         G_Mixer;
+extern PluginHost    G_PluginHost;
+extern unsigned      G_beats;
+extern gdMainWindow *mainWin;
+
+
+PluginHost::PluginHost() {
+
+       /* initially we fill vstTimeInfo with trash. Only when the plugin requests
+        * the opcode we load the right infos from G_Mixer. */
+
+       vstTimeInfo.samplePos          = 0.0;
+       vstTimeInfo.sampleRate         = G_Conf.samplerate;
+       vstTimeInfo.nanoSeconds        = 0.0;
+       vstTimeInfo.ppqPos             = 0.0;
+       vstTimeInfo.tempo              = 120.0;
+       vstTimeInfo.barStartPos        = 0.0;
+       vstTimeInfo.cycleStartPos      = 0.0;
+       vstTimeInfo.cycleEndPos        = 0.0;
+       vstTimeInfo.timeSigNumerator   = 4;
+       vstTimeInfo.timeSigDenominator = 4;
+       vstTimeInfo.smpteOffset        = 0;
+       vstTimeInfo.smpteFrameRate     = 1;
+       vstTimeInfo.samplesToNextClock = 0;
+       vstTimeInfo.flags              = 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+PluginHost::~PluginHost() {}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int PluginHost::allocBuffers() {
+
+       /** FIXME - ERROR CHECKING! */
+
+       /* never, ever use G_Conf.buffersize to alloc these chunks of memory.
+        * If you use JACK, that value would be meaningless. Always refer to
+        * kernelAudio::realBufsize. */
+
+       int bufSize = kernelAudio::realBufsize*sizeof(float);
+
+       bufferI    = (float **) malloc(2 * sizeof(float*));
+       bufferI[0] =  (float *) malloc(bufSize);
+       bufferI[1] =  (float *) malloc(bufSize);
+
+       bufferO    = (float **) malloc(2 * sizeof(float*));
+       bufferO[0] =  (float *) malloc(bufSize);
+       bufferO[1] =  (float *) malloc(bufSize);
+
+       memset(bufferI[0], 0, bufSize);
+       memset(bufferI[1], 0, bufSize);
+       memset(bufferO[0], 0, bufSize);
+       memset(bufferO[1], 0, bufSize);
+
+       gLog("[pluginHost] buffers allocated, buffersize = %d\n", 2*kernelAudio::realBufsize);
+
+       //printOpcodes();
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+VstIntPtr VSTCALLBACK PluginHost::HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) {
+       return G_PluginHost.gHostCallback(effect, opcode, index, value, ptr, opt);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) {
+
+       /* warning: VST headers compiled with DECLARE_VST_DEPRECATED. */
+
+       switch (opcode) {
+
+               /* 0 - Called after a control has changed in the editor and when
+                * the associated parameter should be automated. Index contains the
+                * param, opt the value. Thanks, but we don't need it now. It will
+                * be useful when recording actions from VST (in the future). */
+
+               case audioMasterAutomate:
+                       return 0;
+
+               /* 1 - host version (2.4) */
+
+               case audioMasterVersion:
+                       return kVstVersion;
+
+               /* 3 - Give idle time to Host application, e.g. if plug-in editor is
+                * doing mouse tracking in a modal loop. This a is multithread app,
+                * we don't need it. */
+
+               case audioMasterIdle:
+                       return 0;
+
+               /* 6 - tells the host that the plugin is an instrument. Deprecated. */
+
+               case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
+                       return 0;
+
+               /* 7 - time infos */
+
+               case audioMasterGetTime:
+                       vstTimeInfo.samplePos          = G_Mixer.actualFrame;
+                       vstTimeInfo.sampleRate         = G_Conf.samplerate;
+                       vstTimeInfo.tempo              = G_Mixer.bpm;
+                       vstTimeInfo.timeSigNumerator   = G_Mixer.beats;
+                       vstTimeInfo.timeSigDenominator = G_Mixer.bars;
+                       vstTimeInfo.ppqPos             = (G_Mixer.actualFrame / (float) G_Conf.samplerate) * (float) G_Mixer.bpm / 60.0f;
+                       return (VstIntPtr) &vstTimeInfo;
+
+               /* ? - requires a pointer to VstEvents. No vstEvents so far (v0.5.4) */
+
+               case audioMasterProcessEvents:
+                       return 0;
+
+               /* 13 - tells that numInputs/numOutputs are changed. Not supported and
+                * not needed. */
+
+               case audioMasterIOChanged:
+                       return false;
+
+               /* 14 - plugin needs idle calls (outside its editor window). Deprecated */
+
+               case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
+                       return 0;
+
+               /* 15 - requests to resize the editor window. w = index, h = value*/
+
+               case audioMasterSizeWindow: {
+                       gWindow *window = NULL;
+                       for (unsigned i=0; i<masterOut.size && !window; i++)
+                               if (masterOut.at(i)->getPlugin() == effect)
+                                       window = masterOut.at(i)->window;
+
+                       for (unsigned i=0; i<masterIn.size && !window; i++)
+                               if (masterIn.at(i)->getPlugin() == effect)
+                                       window = masterIn.at(i)->window;
+
+                       for (unsigned i=0; i<G_Mixer.channels.size && !window; i++) {
+                               Channel *ch = G_Mixer.channels.at(i);
+                               for (unsigned j=0; j<ch->plugins.size && !window; j++)
+                                       if (ch->plugins.at(j)->getPlugin() == effect)
+                                               window = ch->plugins.at(j)->window;
+                       }
+
+                       if (window) {
+                               gLog("[pluginHost] audioMasterSizeWindow: resizing window from plugin %p\n", (void*) effect);
+                               if (index == 1 || value == 1)
+                                       gLog("[pluginHost] warning: non-sense values!\n");
+                               else
+                                       window->size((int)index, (int)value);
+                               return 1;
+                       }
+                       else {
+                               gLog("[pluginHost] audioMasterSizeWindow: window from plugin %p not found\n", (void*) effect);
+                               return 0;
+                       }
+               }
+
+               /* 16 - sample rate */
+
+               case audioMasterGetSampleRate:
+                       return G_Conf.samplerate;
+
+               /* ?? - buffer size */
+
+               case audioMasterGetBlockSize:
+                       return kernelAudio::realBufsize;
+
+               case audioMasterGetInputLatency:
+                       gLog("[pluginHost] requested opcode 'audioMasterGetInputLatency' (%d)\n", opcode);
+                       return 0;
+
+               case audioMasterGetOutputLatency:
+                       gLog("[pluginHost] requested opcode 'audioMasterGetOutputLatency' (%d)\n", opcode);
+                       return 0;
+
+               /* 23 - wants to know what kind of process is that.
+                * kVstProcessLevelRealtime = currently in audio thread (where
+                * process is called). */
+
+               case audioMasterGetCurrentProcessLevel:
+                       return kVstProcessLevelRealtime;
+
+               /* 32 - vendor name */
+
+               case audioMasterGetVendorString:
+                       strcpy((char*)ptr, "Monocasual");
+                       return 1;
+
+               /* 32 - product name */
+
+               case audioMasterGetProductString:
+                       strcpy((char*)ptr, "Giada");
+                       return 1;
+
+               /* 33 - product version */
+
+               case audioMasterGetVendorVersion:
+                       return (int) VERSIONE_FLOAT * 100;
+
+
+               /* 37 - Plugin asks Host if it implements the feature text. */
+
+               case audioMasterCanDo:
+                       gLog("[pluginHost] audioMasterCanDo: %s\n", (char*)ptr);
+                       if (!strcmp((char*)ptr, "sizeWindow")       ||
+                                       !strcmp((char*)ptr, "sendVstTimeInfo")  ||
+                                       !strcmp((char*)ptr, "sendVstMidiEvent") ||
+                                       !strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime"))
+                               return 1; // we can do all of that
+                       else
+                               return 0;
+
+               /* 42 - Something has changed, update the host's 'multi-fx' display.
+                * Not supported right now, return 0. This opcode deals with the program
+                * changes, more infos http://www.asseca.com/vst-24-specs/amUpdateDisplay.html */
+
+               case audioMasterUpdateDisplay:
+                       return 0;
+
+               case audioMasterGetLanguage:
+                       return kVstLangEnglish;
+
+               /* ?? */
+
+               case audioMasterGetAutomationState:
+                       gLog("[pluginHost] requested opcode 'audioMasterGetAutomationState' (%d)\n", opcode);
+                       return 0;
+
+               /* 43 - It tells the Host that if it needs to, it has to record
+                * automation data for this control. In other words this opcode is fired
+                * when the user starts to tweak a parameter with the mouse.
+                * Useful when the plugin actions will be recorded. */
+
+               case audioMasterBeginEdit:
+                       return 0;
+
+               /* 44 - no more interaction for the user, started with the previous
+                * opcode. */
+
+               case audioMasterEndEdit:
+                       return 0;
+
+               default:
+                       gLog("[pluginHost] FIXME: host callback called with opcode %d\n", opcode);
+                       return 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) {
+
+       Plugin *p    = new Plugin();
+       bool success = true;
+
+       gVector <Plugin *> *pStack;
+       pStack = getStack(stackType, ch);
+
+       if (!p->load(fname)) {
+               //delete p;
+               //return 0;
+               success = false;
+       }
+
+       /* if the load failed we add a 'dead' plugin into the stack. This is
+        * useful to report a missing plugin. */
+
+       if (!success) {
+               pStack->add(p);
+               return 0;
+       }
+
+       /* otherwise let's try to initialize it. */
+
+       else {
+
+               /* try to init the plugin. If fails, delete it and return error. */
+
+               if (!p->init(&PluginHost::HostCallback)) {
+                       delete p;
+                       return 0;
+               }
+
+               /* plugin setup */
+
+               p->setup(G_Conf.samplerate, kernelAudio::realBufsize);
+
+               /* try to add the new plugin until succeed */
+
+               int lockStatus;
+               while (true) {
+                       lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
+                       if (lockStatus == 0) {
+                               pStack->add(p);
+                               pthread_mutex_unlock(&G_Mixer.mutex_plugins);
+                               break;
+                       }
+               }
+
+               char name[256]; p->getName(name);
+               gLog("[pluginHost] plugin id=%d loaded (%s), stack type=%d, stack size=%d\n", p->getId(), name, stackType, pStack->size);
+
+               /* p->resume() is suggested. Who knows... */
+
+               p->resume();
+
+               return 1;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::processStack(float *buffer, int stackType, Channel *ch) {
+
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+
+       /* empty stack, stack not found or mixer not ready: do nothing */
+       /// TODO - join evaluation
+
+       if (!G_Mixer.ready)
+               return;
+       if (pStack == NULL)
+               return;
+       if (pStack->size == 0)
+               return;
+
+       /* converting buffer from Giada to VST */
+
+       for (unsigned i=0; i<kernelAudio::realBufsize; i++) {
+               bufferI[0][i] = buffer[i*2];
+               bufferI[1][i] = buffer[(i*2)+1];
+       }
+
+       /* hardcore processing. At the end we swap input and output, so that
+        * the N-th plugin will process the result of the plugin N-1. */
+
+       for (unsigned i=0; i<pStack->size; i++) {
+               /// TODO - join evaluation
+
+               if (pStack->at(i)->status != 1)
+                       continue;
+               if (pStack->at(i)->suspended)
+                       continue;
+               if (pStack->at(i)->bypass)
+                       continue;
+               if (ch) {   // process events if it's a channel stack
+                       if (ch->type == CHANNEL_MIDI) {
+                               ///gLog("events: %d\n", (((MidiChannel*)ch)->getVstEvents())->numEvents);
+                               pStack->at(i)->processEvents(((MidiChannel*)ch)->getVstEvents());
+                       }
+               }
+               pStack->at(i)->processAudio(bufferI, bufferO, kernelAudio::realBufsize);
+               bufferI = bufferO;
+       }
+
+       /* converting buffer from VST to Giada. A note for the future: if we
+        * overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */
+
+       for (unsigned i=0; i<kernelAudio::realBufsize; i++) {
+               buffer[i*2]     = bufferO[0][i];
+               buffer[(i*2)+1] = bufferO[1][i];
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::processStackOffline(float *buffer, int stackType, Channel *ch, int size) {
+
+       /* call processStack on the entire size of the buffer. How many cycles?
+        * size / (kernelAudio::realBufsize*2) (ie. internal bufsize) */
+
+       /** FIXME 1 - calling processStack is slow, due to its internal buffer
+        * conversions. We should also call processOffline from VST sdk */
+
+       int index = 0;
+       int step  = kernelAudio::realBufsize*2;
+
+       while (index <= size) {
+               int left = index+step-size;
+               if (left < 0)
+                       processStack(&buffer[index], stackType, ch);
+
+       /** FIXME 2 - we left out the last part of buffer, because size % step != 0.
+        * we should process the last chunk in a separate buffer, padded with 0 */
+
+               //else
+               //      gLog("chunk of buffer left, size=%d\n", left);
+
+               index+=step;
+       }
+
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Plugin *PluginHost::getPluginById(int id, int stackType, Channel *ch) {
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+       for (unsigned i=0; i<pStack->size; i++) {
+               if (pStack->at(i)->getId() == id)
+                       return pStack->at(i);
+       }
+       return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Plugin *PluginHost::getPluginByIndex(int index, int stackType, Channel *ch) {
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+       if (pStack->size == 0)
+               return NULL;
+       if ((unsigned) index >= pStack->size)
+               return NULL;
+       return pStack->at(index);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::freeStack(int stackType, Channel *ch) {
+
+       gVector <Plugin *> *pStack;
+       pStack = getStack(stackType, ch);
+
+       if (pStack->size == 0)
+               return;
+
+       int lockStatus;
+       while (true) {
+               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
+               if (lockStatus == 0) {
+                       for (unsigned i=0; i<pStack->size; i++) {
+                               if (pStack->at(i)->status == 1) {  // only if plugin is ok
+                                       pStack->at(i)->suspend();
+                                       pStack->at(i)->close();
+                               }
+                               delete pStack->at(i);
+                       }
+                       pStack->clear();
+                       pthread_mutex_unlock(&G_Mixer.mutex_plugins);
+                       break;
+               }
+       }
+
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::freeAllStacks() {
+       freeStack(PluginHost::MASTER_OUT);
+       freeStack(PluginHost::MASTER_IN);
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               freeStack(PluginHost::CHANNEL, G_Mixer.channels.at(i));
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::freePlugin(int id, int stackType, Channel *ch) {
+
+       gVector <Plugin *> *pStack;
+       pStack = getStack(stackType, ch);
+
+       /* try to delete the plugin until succeed. G_Mixer has priority. */
+
+       for (unsigned i=0; i<pStack->size; i++)
+               if (pStack->at(i)->getId() == id) {
+
+                       if (pStack->at(i)->status == 0) { // no frills if plugin is missing
+                               delete pStack->at(i);
+                               pStack->del(i);
+                               return;
+                       }
+                       else {
+                               int lockStatus;
+                               while (true) {
+                                       lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
+                                       if (lockStatus == 0) {
+                                               pStack->at(i)->suspend();
+                                               pStack->at(i)->close();
+                                               delete pStack->at(i);
+                                               pStack->del(i);
+                                               pthread_mutex_unlock(&G_Mixer.mutex_plugins);
+                                               gLog("[pluginHost] plugin id=%d removed\n", id);
+                                               return;
+                                       }
+                                       //else
+                                               //gLog("[pluginHost] waiting for mutex...\n");
+                               }
+                       }
+               }
+       gLog("[pluginHost] plugin id=%d not found\n", id);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, Channel *ch) {
+
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+
+       int lockStatus;
+       while (true) {
+               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
+               if (lockStatus == 0) {
+                       pStack->swap(indexA, indexB);
+                       pthread_mutex_unlock(&G_Mixer.mutex_plugins);
+                       gLog("[pluginHost] plugin at index %d and %d swapped\n", indexA, indexB);
+                       return;
+               }
+               //else
+                       //gLog("[pluginHost] waiting for mutex...\n");
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int PluginHost::getPluginIndex(int id, int stackType, Channel *ch) {
+
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+
+       for (unsigned i=0; i<pStack->size; i++)
+               if (pStack->at(i)->getId() == id)
+                       return i;
+       return -1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gVector <Plugin *> *PluginHost::getStack(int stackType, Channel *ch) {
+       switch(stackType) {
+               case MASTER_OUT:
+                       return &masterOut;
+               case MASTER_IN:
+                       return &masterIn;
+               case CHANNEL:
+                       return &ch->plugins;
+               default:
+                       return NULL;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+VstMidiEvent *PluginHost::createVstMidiEvent(uint32_t msg)
+{
+       VstMidiEvent *e = (VstMidiEvent*) malloc(sizeof(VstMidiEvent));
+
+       /* type = two types of events: MIDI event and MIDI system exclusive
+        * (aka sysex, not implemented). */
+
+       e->type     = kVstMidiType;
+       e->byteSize = sizeof(VstMidiEvent);
+
+       /* deltaFrames = sample frames related to the current block start
+        * sample position. */
+
+       e->deltaFrames = 0;
+
+       /* flags = kVstMidiEventIsRealtime means that this event is played
+        * live (not in playback from a sequencer track). This allows the
+        * Plug-In to handle these flagged events with higher priority,
+        * especially when the Plug-In has a big latency */
+
+       e->flags = kVstMidiEventIsRealtime;
+
+       /* midiData = 1 to 3 MIDI bytes; midiData[3] is reserved (zero) */
+
+       e->midiData[0] = kernelMidi::getB1(msg); // note on/off + channel
+       e->midiData[1] = kernelMidi::getB2(msg); // note number
+       e->midiData[2] = kernelMidi::getB3(msg); // velocity
+       e->midiData[3] = 0;
+
+       /* noteLength = (in sample frames) of entire note, if available,
+        * else 0 */
+
+       e->noteLength = 0;
+
+       /* noteOffset = offset (in sample frames) into note from note start
+        * if available, else 0 */
+
+       e->noteOffset = 0;
+
+       /* noteOffVelocity =  Note Off Velocity [0, 127]. */
+
+       e->noteOffVelocity = 0;
+
+       return e;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+unsigned PluginHost::countPlugins(int stackType, Channel *ch) {
+       gVector <Plugin *> *pStack = getStack(stackType, ch);
+       return pStack->size;
+}
+
+
+#endif // #ifdef WITH_VST
diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h
new file mode 100644 (file)
index 0000000..58907ad
--- /dev/null
@@ -0,0 +1,132 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * pluginHost
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifdef WITH_VST
+
+#ifndef __PLUGIN_HOST_
+#define __PLUGIN_HOST_
+
+#include "../utils/utils.h"
+#include "../gui/elems/ge_window.h"
+#include "plugin.h"
+#include "init.h"
+#include "const.h"
+
+
+class PluginHost {
+
+private:
+
+       /* VSTs have a different buffer model:
+        *
+        * buffer[0] = channel left
+        * buffer[1] = channel right
+        * buffer[0][....] = all signals from left chan
+        * buffer[1][....] = all signals from right chan */
+
+       float **bufferI;
+       float **bufferO;
+
+       /* VST struct containing infos on tempo (bpm, freq, smtpe, ...). */
+
+       VstTimeInfo vstTimeInfo;
+
+public:
+
+       /* stack types. Use them together with getStack() in order to geta
+        * pointer to the right stack. */
+
+       enum stackType {
+               MASTER_OUT,
+               MASTER_IN,
+               CHANNEL
+       };
+
+       /* stack of Plugins */
+
+       gVector <Plugin *> masterOut;
+       gVector <Plugin *> masterIn;
+
+       PluginHost();
+       ~PluginHost();
+
+       int allocBuffers();
+
+       /* The plugin can ask the host if it supports a given capability,
+        * which is done through the HostCallback() function.
+        *
+        * Why static? This is a callback attached to each plugin in the stack
+        * and C++ callback functions need to be static when declared in class.
+        *
+        * OPCODE LIST:
+        * base version: vstsdk2.4/pluginterfaces/aeffect.h (vst 1.x)
+        * enhanced v. : vstsdk2.4/pluginterfaces/effectx.h (vst 2.x) */
+
+       static VstIntPtr VSTCALLBACK HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt);
+       VstIntPtr gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt);
+
+       int addPlugin(const char *fname, int stackType, class Channel *ch=NULL);
+
+       void processEvents(float *buffer, class Channel *ch);
+
+       /* processStack
+        * apply the fx list to the buffer. */
+
+       void processStack(float *buffer, int stackType, class Channel *ch=NULL);
+
+       /* processStackOffline
+        * apply the fx list to a longer chunk of data */
+
+       void processStackOffline(float *buffer, int stackType, class Channel *ch, int size);
+
+       /* createVstMidiEvent
+        * return a pointer to a new VstMidiEvent structure. */
+
+       VstMidiEvent *createVstMidiEvent(uint32_t msg);
+
+       gVector <Plugin *> *getStack(int stackType, class Channel *ch=NULL);
+
+       Plugin *getPluginById(int id, int stackType, class Channel *ch=NULL);
+
+       Plugin *getPluginByIndex(int index, int stackType, class Channel *ch=NULL);
+
+       int getPluginIndex(int id, int stackType, class Channel *ch=NULL);
+
+       unsigned countPlugins(int stackType, class Channel *ch=NULL);
+
+       void freeStack(int stackType, class Channel *ch=NULL);
+
+       void freeAllStacks();
+
+       void freePlugin(int id, int stackType, class Channel *ch=NULL);
+
+       void swapPlugin(unsigned indexA, unsigned indexB, int stackType, class Channel *ch=NULL);
+};
+#endif
+
+#endif // #ifdef WITH_VST
diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp
new file mode 100644 (file)
index 0000000..73d9b38
--- /dev/null
@@ -0,0 +1,697 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * recorder
+ * Action recorder.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <math.h>
+#include "recorder.h"
+#include "const.h"
+#include "mixer.h"
+#include "mixerHandler.h"
+#include "kernelAudio.h"
+#include "pluginHost.h"
+#include "kernelMidi.h"
+#include "patch.h"
+#include "conf.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "../utils/log.h"
+#include "../utils/utils.h"
+
+
+#ifdef WITH_VST
+extern PluginHost G_PluginHost;
+#endif
+
+
+extern Mixer G_Mixer;
+extern Patch f_patch;
+extern Conf     G_Conf;
+
+
+namespace recorder
+{
+gVector<int> frames;
+gVector< gVector<action*> > global;
+gVector<action*>  actions;
+
+bool active = false;
+bool sortedActions = false;
+
+composite cmp;
+
+
+/* ------------------------------------------------------------------ */
+
+
+void init()
+{
+       sortedActions = false;
+       active = false;
+       clearAll();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool canRec(Channel *ch)
+{
+       /* NO recording if:
+        * recorder is inactive
+        * mixer is not running
+        * mixer is recording a take in this channel ch
+        * channel is empty */
+
+       if (!active || !G_Mixer.running || G_Mixer.chanInput == ch || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL))
+               return 0;
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void rec(int index, int type, int frame, uint32_t iValue, float fValue)
+{
+       /* make sure frame is even */
+
+       if (frame % 2 != 0)
+               frame++;
+
+       /* allocating the action */
+
+       action *a = (action*) malloc(sizeof(action));
+       a->chan   = index;
+       a->type   = type;
+       a->frame  = frame;
+       a->iValue = iValue;
+       a->fValue = fValue;
+
+       /* check if the frame exists in the stack. If it exists, we don't extend
+        * the stack, but we add (or push) a new action to it. */
+
+       int frameToExpand = frames.size;
+       for (int i=0; i<frameToExpand; i++)
+               if (frames.at(i) == frame) {
+                       frameToExpand = i;
+                       break;
+               }
+
+       /* espansione dello stack frames nel caso l'azione ricada in frame
+        * non precedentemente memorizzati (frameToExpand == frames.size).
+        * Espandere frames è facile, basta aggiungere un frame in coda.
+        * Espandere global è più complesso: bisogna prima allocare una
+        * cella in global (per renderlo parallelo a frames) e poi
+        * inizializzare il suo sub-stack (di action). */
+
+       if (frameToExpand == (int) frames.size) {
+               frames.add(frame);
+               global.add(actions);                                                    // array of actions added
+               global.at(global.size-1).add(a);        // action added
+       }
+       else {
+
+               /* no duplicates, please */
+
+               for (unsigned t=0; t<global.at(frameToExpand).size; t++) {
+                       action *ac = global.at(frameToExpand).at(t);
+                       if (ac->chan   == index  &&
+                           ac->type   == type   &&
+                           ac->frame  == frame  &&
+                           ac->iValue == iValue &&
+                           ac->fValue == fValue)
+                               return;
+               }
+
+               global.at(frameToExpand).add(a);                // expand array
+       }
+
+       /* if WITH_VST create a new VST event and attach it to our action.
+        * Nota bene: the VST event occurs on localFrame=0: this is a
+        * user-generated event after all! */
+
+#ifdef WITH_VST
+       if (type == ACTION_MIDI)
+               a->event = G_PluginHost.createVstMidiEvent(a->iValue);
+#endif
+
+       /* don't activate the channel (readActions == false), it's up to
+        * the other layers */
+
+       Channel *ch = G_Mixer.getChannelByIndex(index);
+       ch->hasActions = true;
+
+       sortedActions = false;
+
+       gLog("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+               a->type, a->frame, a->chan, a->iValue, a->iValue, a->fValue);
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void clearChan(int index)
+{
+       gLog("[REC] clearing chan %d...\n", index);
+
+       for (unsigned i=0; i<global.size; i++) {        // for each frame i
+               unsigned j=0;
+               while (true) {
+                       if (j == global.at(i).size) break;        // for each action j of frame i
+                       action *a = global.at(i).at(j);
+                       if (a->chan == index)   {
+#ifdef WITH_VST
+                               if (a->type == ACTION_MIDI)
+                                       free(a->event);
+#endif
+                               free(a);
+                               global.at(i).del(j);
+                       }
+                       else
+                               j++;
+               }
+       }
+
+       Channel *ch = G_Mixer.getChannelByIndex(index);
+       ch->hasActions = false;
+       optimize();
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void clearAction(int index, char act)
+{
+       gLog("[REC] clearing action %d from chan %d...\n", act, index);
+       for (unsigned i=0; i<global.size; i++) {                                                // for each frame i
+               unsigned j=0;
+               while (true) {                                   // for each action j of frame i
+                       if (j == global.at(i).size)
+                               break;
+                       action *a = global.at(i).at(j);
+                       if (a->chan == index && (act & a->type) == a->type)     { // bitmask
+                               free(a);
+                               global.at(i).del(j);
+                       }
+                       else
+                               j++;
+               }
+       }
+       Channel *ch = G_Mixer.getChannelByIndex(index);
+       ch->hasActions = false;   /// FIXME - why this? Isn't it useless if we call chanHasActions?
+       optimize();
+       chanHasActions(index);    /// FIXME
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue, float fValue)
+{
+       /* make sure frame is even */
+
+       if (frame % 2 != 0)
+               frame++;
+               
+       /* find the frame 'frame' */
+
+       bool found = false;
+       for (unsigned i=0; i<frames.size && !found; i++) {
+               if (frames.at(i) == frame) {
+
+                       /* find the action in frame i */
+
+                       for (unsigned j=0; j<global.at(i).size; j++) {
+                               action *a = global.at(i).at(j);
+
+                               /* action comparison logic */
+
+                               bool doit = (a->chan == chan && a->type == (type & a->type));
+                               if (checkValues)
+                                       doit &= (a->iValue == iValue && a->fValue == fValue);
+
+                               if (doit) {
+                                       int lockStatus = 0;
+                                       while (lockStatus == 0) {
+                                               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs);
+                                               if (lockStatus == 0) {
+#ifdef WITH_VST
+                                                       if (type == ACTION_MIDI)
+                                                               free(a->event);
+#endif
+                                                       free(a);
+                                                       global.at(i).del(j);
+                                                       pthread_mutex_unlock(&G_Mixer.mutex_recs);
+                                                       found = true;
+                                                       break;
+                                               }
+                                               else
+                                                       gLog("[REC] delete action: waiting for mutex...\n");
+                                       }
+                               }
+                       }
+               }
+       }
+       if (found) {
+               optimize();
+               chanHasActions(chan);
+               gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+                       type, frame, chan, iValue, iValue, fValue);
+       }
+       else
+               gLog("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+                       type, frame, chan, iValue, iValue, fValue);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void deleteActions(int chan, int frame_a, int frame_b, char type)
+{
+       sortActions();
+       gVector<int> dels;
+
+       for (unsigned i=0; i<frames.size; i++)
+               if (frames.at(i) > frame_a && frames.at(i) < frame_b)
+                       dels.add(frames.at(i));
+
+       for (unsigned i=0; i<dels.size; i++)
+               deleteAction(chan, dels.at(i), type, false); // false == don't check values
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void clearAll()
+{
+       while (global.size > 0) {
+               for (unsigned i=0; i<global.size; i++) {
+                       for (unsigned k=0; k<global.at(i).size; k++) {
+#ifdef WITH_VST
+                               if (global.at(i).at(k)->type == ACTION_MIDI)
+                                       free(global.at(i).at(k)->event);
+#endif
+                               free(global.at(i).at(k));                                                                       // free action
+                       }
+                       global.at(i).clear();                                                                                           // free action container
+                       global.del(i);
+               }
+       }
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               G_Mixer.channels.at(i)->hasActions  = false;
+               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
+                       ((SampleChannel*)G_Mixer.channels.at(i))->readActions = false;
+       }
+
+       global.clear();
+       frames.clear();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void optimize()
+{
+       /* do something until the i frame is empty. */
+
+       unsigned i = 0;
+       while (true) {
+               if (i == global.size) return;
+               if (global.at(i).size == 0) {
+                       global.del(i);
+                       frames.del(i);
+               }
+               else
+                       i++;
+       }
+
+       sortActions();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void sortActions()
+{
+       if (sortedActions)
+               return;
+       for (unsigned i=0; i<frames.size; i++)
+               for (unsigned j=0; j<frames.size; j++)
+                       if (frames.at(j) > frames.at(i)) {
+                               frames.swap(j, i);
+                               global.swap(j, i);
+                       }
+       sortedActions = true;
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void updateBpm(float oldval, float newval, int oldquanto)
+{
+       for (unsigned i=0; i<frames.size; i++) {
+
+               float frame  = ((float) frames.at(i)/newval) * oldval;
+               frames.at(i) = (int) frame;
+
+               /* the division up here cannot be precise. A new frame can be 44099
+                * and the quantizer set to 44100. That would mean two recs completely
+                * useless. So we compute a reject value ('scarto'): if it's lower
+                * than 6 frames the new frame is collapsed with a quantized frame. */
+               /** CHECKME - maybe 6 frames are too low */
+
+               if (frames.at(i) != 0) {
+                       int scarto = oldquanto % frames.at(i);
+                       if (scarto > 0 && scarto <= 6)
+                               frames.at(i) = frames.at(i) + scarto;
+               }
+
+               /* never ever have odd frames. */
+
+               if (frames.at(i) % 2 != 0)
+                       frames.at(i)++;
+       }
+
+       /* update structs */
+
+       for (unsigned i=0; i<frames.size; i++) {
+               for (unsigned j=0; j<global.at(i).size; j++) {
+                       action *a = global.at(i).at(j);
+                       a->frame = frames.at(i);
+               }
+       }
+
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void updateSamplerate(int systemRate, int patchRate)
+{
+       /* diff ratio: systemRate / patchRate
+        * e.g.  44100 / 96000 = 0.4... */
+
+       if (systemRate == patchRate)
+               return;
+
+       gLog("[REC] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate);
+
+       float ratio = systemRate / (float) patchRate;
+       for (unsigned i=0; i<frames.size; i++) {
+
+               gLog("[REC]    oldFrame = %d", frames.at(i));
+
+               float newFrame = frames.at(i);
+               newFrame = floorf(newFrame * ratio);
+
+               frames.at(i) = (int) newFrame;
+
+               if (frames.at(i) % 2 != 0)
+                       frames.at(i)++;
+
+               gLog(", newFrame = %d\n", frames.at(i));
+       }
+
+       /* update structs */
+
+       for (unsigned i=0; i<frames.size; i++) {
+               for (unsigned j=0; j<global.at(i).size; j++) {
+                       action *a = global.at(i).at(j);
+                       a->frame = frames.at(i);
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void expand(int old_fpb, int new_fpb)
+{
+       /* this algorithm requires multiple passages if we expand from e.g. 2
+        * to 16 beats, precisely 16 / 2 - 1 = 7 times (-1 is the first group,
+        * which exists yet). If we expand by a non-multiple, the result is zero,
+        * due to float->int implicit cast */
+
+       unsigned pass = (int) (new_fpb / old_fpb) - 1;
+       if (pass == 0) pass = 1;
+
+       unsigned init_fs = frames.size;
+
+       for (unsigned z=1; z<=pass; z++) {
+               for (unsigned i=0; i<init_fs; i++) {
+                       unsigned newframe = frames.at(i) + (old_fpb*z);
+                       frames.add(newframe);
+                       global.add(actions);
+                       for (unsigned k=0; k<global.at(i).size; k++) {
+                               action *a = global.at(i).at(k);
+                               rec(a->chan, a->type, newframe, a->iValue, a->fValue);
+                       }
+               }
+       }
+       gLog("[REC] expanded recs\n");
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void shrink(int new_fpb)
+{
+       /* easier than expand(): here we delete eveything beyond old_framesPerBars. */
+
+       unsigned i=0;
+       while (true) {
+               if (i == frames.size) break;
+
+               if (frames.at(i) >= new_fpb) {
+                       for (unsigned k=0; k<global.at(i).size; k++)
+                               free(global.at(i).at(k));                       // free action
+                       global.at(i).clear();                                                           // free action container
+                       global.del(i);                                                                                  // shrink global
+                       frames.del(i);                                                                                  // shrink frames
+               }
+               else
+                       i++;
+       }
+       optimize();
+       gLog("[REC] shrinked recs\n");
+       //print();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void chanHasActions(int index)
+{
+       Channel *ch = G_Mixer.getChannelByIndex(index);
+       if (global.size == 0) {
+               ch->hasActions = false;
+               return;
+       }
+       for (unsigned i=0; i<global.size && !ch->hasActions; i++) {
+               for (unsigned j=0; j<global.at(i).size && !ch->hasActions; j++) {
+                       if (global.at(i).at(j)->chan == index)
+                               ch->hasActions = true;
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue)
+{
+       sortActions();  // mandatory
+
+       unsigned i=0;
+       while (i < frames.size && frames.at(i) <= frame) i++;
+
+       if (i == frames.size)   // no further actions past 'frame'
+               return -1;
+
+       for (; i<global.size; i++)
+               for (unsigned j=0; j<global.at(i).size; j++) {
+                       action *a = global.at(i).at(j);
+                       if (a->chan == chan && (type & a->type) == a->type) {
+                               if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) {
+                                       *out = global.at(i).at(j);
+                                       return 1;
+                               }
+                       }
+               }
+
+       return -2;   // no 'type' actions found
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int getAction(int chan, char action, int frame, struct action **out)
+{
+       for (unsigned i=0; i<global.size; i++)
+               for (unsigned j=0; j<global.at(i).size; j++)
+                       if (frame  == global.at(i).at(j)->frame &&
+                                       action == global.at(i).at(j)->type &&
+                                       chan   == global.at(i).at(j)->chan)
+                       {
+                               *out = global.at(i).at(j);
+                               return 1;
+                       }
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void startOverdub(int index, char actionMask, int frame)
+{
+       /* prepare the composite struct */
+
+       if (actionMask == ACTION_KEYS) {
+               cmp.a1.type = ACTION_KEYPRESS;
+               cmp.a2.type = ACTION_KEYREL;
+       }
+       else {
+               cmp.a1.type = ACTION_MUTEON;
+               cmp.a2.type = ACTION_MUTEOFF;
+       }
+       cmp.a1.chan  = index;
+       cmp.a2.chan  = index;
+       cmp.a1.frame = frame;
+       // cmp.a2.frame doesn't exist yet
+
+       /* avoid underlying action truncation: if action2.type == nextAction:
+        * you are in the middle of a composite action, truncation needed */
+
+       rec(index, cmp.a1.type, frame);
+
+       action *act = NULL;
+       int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act);
+       if (res == 1) {
+               if (act->type == cmp.a2.type) {
+                       int truncFrame = cmp.a1.frame-kernelAudio::realBufsize;
+                       if (truncFrame < 0)
+                               truncFrame = 0;
+                       gLog("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type);
+                       rec(index, cmp.a2.type, truncFrame);
+               }
+       }
+
+       SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(index);
+       ch->readActions = false;   // don't use disableRead()
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void stopOverdub(int frame)
+{
+       cmp.a2.frame  = frame;
+       bool ringLoop = false;
+       bool nullLoop = false;
+
+       /* ring loop verification, i.e. a composite action with key_press at
+        * frame N and key_release at frame M, with M <= N */
+
+       if (cmp.a2.frame < cmp.a1.frame) {
+               ringLoop = true;
+               gLog("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
+               rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames);     // record at the end of the sequencer
+       }
+       else
+       if (cmp.a2.frame == cmp.a1.frame) {
+               nullLoop = true;
+               gLog("[REC]  null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
+               deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values
+       }
+
+       SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(cmp.a2.chan);
+       ch->readActions = false;      // don't use disableRead()
+
+       /* remove any nested action between keypress----keyrel, then record */
+
+       if (!nullLoop)
+               deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type);
+               deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type);
+
+       if (!ringLoop && !nullLoop) {
+               rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
+
+               /* avoid underlying action truncation, if keyrel happens inside a
+               * composite action */
+
+               action *act = NULL;
+               int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act);
+               if (res == 1) {
+                       if (act->type == cmp.a2.type) {
+                               gLog("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type);
+                               deleteAction(act->chan, act->frame, act->type, false); // false == don't check values
+                       }
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void print()
+{
+       gLog("[REC] ** print debug **\n");
+       for (unsigned i=0; i<global.size; i++) {
+               gLog("  frame %d\n", frames.at(i));
+               for (unsigned j=0; j<global.at(i).size; j++) {
+                       gLog("    action %d | chan %d | frame %d\n", global.at(i).at(j)->type, global.at(i).at(j)->chan, global.at(i).at(j)->frame);
+               }
+       }
+}
+
+} // namespace
diff --git a/src/core/recorder.h b/src/core/recorder.h
new file mode 100644 (file)
index 0000000..6c9c65e
--- /dev/null
@@ -0,0 +1,192 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * recorder
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef RECORDER_H
+#define RECORDER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "../utils/utils.h"
+#include "const.h"
+#include "mixer.h"
+
+#ifdef WITH_VST
+
+/* before including aeffetx(x).h we must define __cdecl, otherwise VST
+ * headers can't be compiled correctly. In windows __cdecl is already
+ * defined. */
+
+       #ifdef __GNUC__
+               #ifndef _WIN32
+                       #define __cdecl
+               #endif
+       #endif
+       #include "../deps/vst/aeffectx.h"
+#endif
+
+/*
+ * [global0]-->[gVector<_action*>0]-->[a0][a1][a2]                             0[frames1]
+ * [global1]-->[gVector<_action*>1]-->[a0][a1][a2]                             1[frames2]
+ * [global2]-->[gVector<_action*>2]-->[a0][a1][a2]                             2[frames3]
+ * [global3]-->[gVector<_action*>3]-->[a0][a1][a2]                             3[frames4]
+ * */
+
+namespace recorder {
+
+/* action
+ * struct containing fields to describe an atomic action. Note from
+ * VST sdk: parameter values, like all VST parameters, are declared as
+ * floats with an inclusive range of 0.0 to 1.0 (fValue). */
+
+struct action {
+       int      chan;    // channel index, i.e. Channel->index
+       int      type;
+       int      frame;   // redundant info, used by helper functions
+       float    fValue;  // used only for envelopes (volumes, vst params).
+       uint32_t iValue;  // used only for MIDI events
+
+       /* if VST store here a pointer to a vstEvent. */
+
+#ifdef WITH_VST
+       VstMidiEvent *event;
+#endif
+};
+
+/* composite
+ * a group of two actions (keypress+keyrel, muteon+muteoff) used during
+ * the overdub process */
+
+struct composite {
+       action a1;
+       action a2;
+};
+
+extern gVector<int>  frames;                                         // frame counter (sentinel) frames.size == global.size
+extern gVector< gVector<action*> > global;     // container of containers of actions
+extern gVector<action*>  actions;                                  // container of actions
+
+extern bool active;
+extern bool sortedActions;                  // are actions sorted via sortActions()?
+
+/* init
+ * everything starts from here. */
+
+void init();
+
+/* chanHasActions
+ * Check if the channel has at least one action recorded. If false, sets
+ * ch->hasActions = false. Used after an action deletion. */
+
+void chanHasActions(int chan);
+
+/* canRec
+ * can a channel rec an action? Call this one BEFORE rec(). */
+
+bool canRec(Channel *ch);
+
+/* rec
+ * record an action. */
+
+void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f);
+
+/* clearChan
+ * clear all actions from a channel. */
+
+void clearChan(int chan);
+
+/* clearAction
+ * clear the 'action' action type from a channel. */
+
+void clearAction(int chan, char action);
+
+/* deleteAction
+ * delete ONE action. Useful in the action editor. 'type' can be a mask. */
+
+void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue=0, float fValue=0.0);
+
+/* deleteActions
+ * delete A RANGE of actions from frame_a to frame_b in channel 'chan'.
+ * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */
+
+void deleteActions(int chan, int frame_a, int frame_b, char type);
+
+/* clearAll
+ * delete everything. */
+
+void clearAll();
+
+/* optimize
+ * clear frames without actions. */
+
+void optimize();
+
+/* sortActions
+ * sorts actions by frame, asc mode. */
+
+void sortActions();
+
+/* updateBpm
+ * reassign frames by calculating the new bpm value. */
+
+void updateBpm(float oldval, float newval, int oldquanto);
+
+/* updateSamplerate
+ * reassign frames taking in account the samplerate. If f_system ==
+ * f_patch nothing changes, otherwise the conversion is mandatory. */
+
+void updateSamplerate(int systemRate, int patchRate);
+
+void expand(int old_fpb, int new_fpb);
+void shrink(int new_fpb);
+
+/* getNextAction
+ * return the nearest action in chan 'chan' of type 'action' starting
+ * from 'frame'. Action can be a bitmask. If iValue != -1 search for
+ * next action with iValue == iValue: useful for MIDI key_release. */
+
+int getNextAction(int chan, char action, int frame, struct action **out, uint32_t iValue=0);
+
+/* getAction
+ * return a pointer to action in chan 'chan' of type 'action' at frame
+ * 'frame'. */
+
+int getAction(int chan, char action, int frame, struct action **out);
+
+/* start/endOverdub */
+
+void startOverdub(int chan, char action, int frame);
+void stopOverdub(int frame);
+
+/* print
+ * debug of the frame stack. */
+
+void print();
+
+}  // namespace
+
+#endif
diff --git a/src/core/sampleChannel.cpp b/src/core/sampleChannel.cpp
new file mode 100644 (file)
index 0000000..81ba29f
--- /dev/null
@@ -0,0 +1,1036 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <math.h>
+#include "../utils/log.h"
+#include "sampleChannel.h"
+#include "patch.h"
+#include "conf.h"
+#include "wave.h"
+#include "pluginHost.h"
+#include "waveFx.h"
+#include "mixerHandler.h"
+#include "kernelMidi.h"
+
+
+extern Patch       G_Patch;
+extern Mixer       G_Mixer;
+extern Conf        G_Conf;
+#ifdef WITH_VST
+extern PluginHost  G_PluginHost;
+#endif
+
+
+SampleChannel::SampleChannel(int bufferSize)
+       : Channel          (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize),
+               frameRewind      (-1),
+               wave             (NULL),
+               tracker          (0),
+               begin            (0),
+               end              (0),
+               pitch            (gDEFAULT_PITCH),
+               boost            (1.0f),
+               mode             (DEFAULT_CHANMODE),
+               qWait              (false),
+               fadeinOn         (false),
+               fadeinVol        (1.0f),
+               fadeoutOn        (false),
+               fadeoutVol       (1.0f),
+               fadeoutTracker   (0),
+               fadeoutStep      (DEFAULT_FADEOUT_STEP),
+         readActions      (true),
+         midiInReadActions(0x0),
+         midiInPitch      (0x0)
+{
+       rsmp_state = src_new(SRC_LINEAR, 2, NULL);
+       pChan      = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+SampleChannel::~SampleChannel()
+{
+       if (wave)
+               delete wave;
+       src_delete(rsmp_state);
+       free(pChan);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::clear()
+{
+       /** TODO - these memsets can be done only if status PLAY (if below),
+        * but it would require extra clearPChan calls when samples stop */
+
+               memset(vChan, 0, sizeof(float) * bufferSize);
+               memset(pChan, 0, sizeof(float) * bufferSize);
+
+       if (status & (STATUS_PLAY | STATUS_ENDING)) {
+               tracker = fillChan(vChan, tracker, 0);
+               if (fadeoutOn && fadeoutType == XFADE) {
+                       gLog("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker);
+                       fadeoutTracker = fillChan(pChan, fadeoutTracker, 0);
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::calcVolumeEnv(int frame)
+{
+       /* method: check this frame && next frame, then calculate delta */
+
+       recorder::action *a0 = NULL;
+       recorder::action *a1 = NULL;
+       int res;
+
+       /* get this action on frame 'frame'. It's unlikely that the action
+        * is not found. */
+
+       res = recorder::getAction(index, ACTION_VOLUME, frame, &a0);
+       if (res == 0)
+               return;
+
+       /* get the action next to this one.
+        * res == -1: a1 not found, this is the last one. Rewind the search
+        * and use action at frame number 0 (actions[0]).
+        * res == -2 ACTION_VOLUME not found. This should never happen */
+
+       res = recorder::getNextAction(index, ACTION_VOLUME, frame, &a1);
+
+       if (res == -1)
+               res = recorder::getAction(index, ACTION_VOLUME, 0, &a1);
+
+       volume_i = a0->fValue;
+       volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::hardStop(int frame)
+{
+       if (frame != 0)        // clear data in range [frame, bufferSize-1]
+               clearChan(vChan, frame);
+       status = STATUS_OFF;
+       sendMidiLplay();
+       reset(frame);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::onBar(int frame)
+{
+       ///if (mode == LOOP_REPEAT && status == STATUS_PLAY)
+       ///     //setXFade(frame);
+       ///     reset(frame);
+
+       if (mode == LOOP_REPEAT) {
+               if (status == STATUS_PLAY)
+                       //setXFade(frame);
+                       reset(frame);
+       }
+       else
+       if (mode == LOOP_ONCE_BAR) {
+               if (status == STATUS_WAIT) {
+                       status  = STATUS_PLAY;
+                       tracker = fillChan(vChan, tracker, frame);
+                       sendMidiLplay();
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int SampleChannel::save(const char *path)
+{
+       return wave->writeData(path);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setBegin(unsigned v)
+{
+       begin   = v;
+       tracker = begin;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setEnd(unsigned v)
+{
+       end = v;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setPitch(float v)
+{
+       pitch = v;
+       rsmp_data.src_ratio = 1/pitch;
+
+       /* if status is off don't slide between frequencies */
+
+       if (status & (STATUS_OFF | STATUS_WAIT))
+               src_set_ratio(rsmp_state, 1/pitch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::rewind()
+{
+       /* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */
+
+       if (wave != NULL) {
+               if ((mode & LOOP_ANY) || (recStatus == REC_READING && (mode & SINGLE_ANY)))
+                       reset(0);  // rewind is user-generated events, always on frame 0
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
+{
+       if (readActions == false)
+               return;
+
+       switch (a->type) {
+               case ACTION_KEYPRESS:
+                       if (mode & SINGLE_ANY)
+                               start(localFrame, false);
+                       break;
+               case ACTION_KEYREL:
+                       if (mode & SINGLE_ANY)
+                               stop();
+                       break;
+               case ACTION_KILLCHAN:
+                       if (mode & SINGLE_ANY)
+                               kill(localFrame);
+                       break;
+               case ACTION_MUTEON:
+                       setMute(true);   // internal mute
+                       break;
+               case ACTION_MUTEOFF:
+                       unsetMute(true); // internal mute
+                       break;
+               case ACTION_VOLUME:
+                       calcVolumeEnv(globalFrame);
+                       break;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::sum(int frame, bool running)
+{
+       if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING))
+               return;
+
+       if (frame != frameRewind) {
+
+               /* volume envelope, only if seq is running */
+
+               if (running) {
+                       volume_i += volume_d;
+                       if (volume_i < 0.0f)
+                               volume_i = 0.0f;
+                       else
+                       if (volume_i > 1.0f)
+                               volume_i = 1.0f;
+               }
+
+               /* fadein or fadeout processes. If mute, delete any signal. */
+
+               /** TODO - big issue: fade[in/out]Vol * internal_volume might be a
+                * bad choice: it causes glitches when muting on and off during a
+                * volume envelope. */
+
+               if (mute || mute_i) {
+                       vChan[frame]   = 0.0f;
+                       vChan[frame+1] = 0.0f;
+               }
+               else
+               if (fadeinOn) {
+                       if (fadeinVol < 1.0f) {
+                               vChan[frame]   *= fadeinVol * volume_i;
+                               vChan[frame+1] *= fadeinVol * volume_i;
+                               fadeinVol += 0.01f;
+                       }
+                       else {
+                               fadeinOn  = false;
+                               fadeinVol = 0.0f;
+                       }
+               }
+               else
+               if (fadeoutOn) {
+                       if (fadeoutVol > 0.0f) { // fadeout ongoing
+                               if (fadeoutType == XFADE) {
+                                       vChan[frame]   *= volume_i;
+                                       vChan[frame+1] *= volume_i;
+                                       vChan[frame]    = pChan[frame]   * fadeoutVol * volume_i;
+                                       vChan[frame+1]  = pChan[frame+1] * fadeoutVol * volume_i;
+                               }
+                               else {
+                                       vChan[frame]   *= fadeoutVol * volume_i;
+                                       vChan[frame+1] *= fadeoutVol * volume_i;
+                               }
+                               fadeoutVol -= fadeoutStep;
+                       }
+                       else {  // fadeout end
+                               fadeoutOn  = false;
+                               fadeoutVol = 1.0f;
+
+                               /* QWait ends with the end of the xfade */
+
+                               if (fadeoutType == XFADE) {
+                                       qWait = false;
+                               }
+                               else {
+                                       if (fadeoutEnd == DO_MUTE)
+                                               mute = true;
+                                       else
+                                       if (fadeoutEnd == DO_MUTE_I)
+                                               mute_i = true;
+                                       else             // DO_STOP
+                                               hardStop(frame);
+                               }
+                       }
+               }
+               else {
+                       vChan[frame]   *= volume_i;
+                       vChan[frame+1] *= volume_i;
+               }
+       }
+       else {
+
+               if (mode & (SINGLE_BASIC | SINGLE_PRESS | SINGLE_RETRIG) ||
+                        (mode == SINGLE_ENDLESS && status == STATUS_ENDING)   ||
+                        (mode & LOOP_ANY && !running))     // stop loops when the seq is off
+               {
+                       status = STATUS_OFF;
+                       sendMidiLplay();
+               }
+
+               /* temporary stop LOOP_ONCE not in ENDING status, otherwise they
+                * would return in wait, losing the ENDING status */
+
+               //if (mode == LOOP_ONCE && status != STATUS_ENDING)
+               if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING) {
+                       status = STATUS_WAIT;
+                       sendMidiLplay();
+               }
+
+               /* check for end of samples. SINGLE_ENDLESS runs forever unless
+                * it's in ENDING mode. */
+
+               reset(frame);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::onZero(int frame)
+{
+       if (wave == NULL)
+               return;
+
+       if (mode & LOOP_ANY) {
+
+               /* do a crossfade if the sample is playing. Regular chanReset
+                * instead if it's muted, otherwise a click occurs */
+
+               if (status == STATUS_PLAY) {
+                       /*
+                       if (mute || mute_i)
+                               reset(frame);
+                       else
+                               setXFade(frame);
+                       */
+                       reset(frame);
+               }
+               else
+               if (status == STATUS_ENDING)
+                       hardStop(frame);
+       }
+
+       if (status == STATUS_WAIT) { /// FIXME - should be inside previous if!
+               status  = STATUS_PLAY;
+               sendMidiLplay();
+               tracker = fillChan(vChan, tracker, frame);
+       }
+
+       if (recStatus == REC_ENDING) {
+               recStatus = REC_STOPPED;
+               setReadActions(false);  // rec stop
+       }
+       else
+       if (recStatus == REC_WAITING) {
+               recStatus = REC_READING;
+               setReadActions(true);   // rec start
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::quantize(int index, int localFrame, int globalFrame)
+{
+       /* skip if LOOP_ANY or not in quantizer-wait mode */
+
+       if ((mode & LOOP_ANY) || !qWait)
+               return;
+
+       /* no fadeout if the sample starts for the first time (from a
+        * STATUS_OFF), it would be meaningless. */
+
+       if (status == STATUS_OFF) {
+               status  = STATUS_PLAY;
+               sendMidiLplay();
+               qWait   = false;
+               tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ???
+       }
+       else
+               //setXFade(localFrame);
+               reset(localFrame);
+
+       /* this is the moment in which we record the keypress, if the
+        * quantizer is on. SINGLE_PRESS needs overdub */
+
+       if (recorder::canRec(this)) {
+               if (mode == SINGLE_PRESS)
+                       recorder::startOverdub(index, ACTION_KEYS, globalFrame);
+               else
+                       recorder::rec(index, ACTION_KEYPRESS, globalFrame);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int SampleChannel::getPosition()
+{
+       if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...)
+               return tracker - begin;
+       else
+               return -1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setMute(bool internal)
+{
+       if (internal) {
+
+               /* global mute is on? don't waste time with fadeout, just mute it
+                * internally */
+
+               if (mute)
+                       mute_i = true;
+               else {
+                       if (isPlaying())
+                               setFadeOut(DO_MUTE_I);
+                       else
+                               mute_i = true;
+               }
+       }
+       else {
+
+               /* internal mute is on? don't waste time with fadeout, just mute it
+                * globally */
+
+               if (mute_i)
+                       mute = true;
+               else {
+
+                       /* sample in play? fadeout needed. Else, just mute it globally */
+
+                       if (isPlaying())
+                               setFadeOut(DO_MUTE);
+                       else
+                               mute = true;
+               }
+       }
+
+       sendMidiLmute();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::unsetMute(bool internal)
+{
+       if (internal) {
+               if (mute)
+                       mute_i = false;
+               else {
+                       if (isPlaying())
+                               setFadeIn(internal);
+                       else
+                               mute_i = false;
+               }
+       }
+       else {
+               if (mute_i)
+                       mute = false;
+               else {
+                       if (isPlaying())
+                               setFadeIn(internal);
+                       else
+                               mute = false;
+               }
+       }
+
+       sendMidiLmute();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::calcFadeoutStep()
+{
+       if (end - tracker < (1 / DEFAULT_FADEOUT_STEP) * 2)
+               fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ???
+       else
+               fadeoutStep = DEFAULT_FADEOUT_STEP;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setReadActions(bool v)
+{
+       if (v)
+               readActions = true;
+       else {
+               readActions = false;
+               if (G_Conf.recsStopOnChanHalt)
+                       kill(0);  /// FIXME - wrong frame value
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setFadeIn(bool internal)
+{
+       if (internal) mute_i = false;  // remove mute before fading in
+       else          mute   = false;
+       fadeinOn  = true;
+       fadeinVol = 0.0f;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setFadeOut(int actionPostFadeout)
+{
+       calcFadeoutStep();
+       fadeoutOn   = true;
+       fadeoutVol  = 1.0f;
+       fadeoutType = FADEOUT;
+       fadeoutEnd      = actionPostFadeout;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::setXFade(int frame)
+{
+       gLog("[xFade] frame=%d tracker=%d\n", frame, tracker);
+
+       calcFadeoutStep();
+       fadeoutOn      = true;
+       fadeoutVol     = 1.0f;
+       fadeoutType    = XFADE;
+       fadeoutTracker = fillChan(pChan, tracker, 0, false);
+       reset(frame);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* on reset, if frame > 0 and in play, fill again pChan to create
+ * something like this:
+ *
+ * |abcdefabcdefab*abcdefabcde|
+ * [old data-----]*[new data--]
+ *
+ * */
+
+void SampleChannel::reset(int frame)
+{
+       //fadeoutTracker = tracker;   // store old frame number for xfade
+       tracker = begin;
+       mute_i  = false;
+       if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING))
+               tracker = fillChan(vChan, tracker, frame);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::empty()
+{
+       status = STATUS_OFF;
+       if (wave) {
+               delete wave;
+               wave = NULL;
+       }
+       status = STATUS_EMPTY;
+       sendMidiLplay();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::pushWave(Wave *w)
+{
+       wave   = w;
+       status = STATUS_OFF;
+       sendMidiLplay();
+       begin  = 0;
+       end    = wave->size;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool SampleChannel::allocEmpty(int frames, int takeId)
+{
+       Wave *w = new Wave();
+       if (!w->allocEmpty(frames))
+               return false;
+
+       char wname[32];
+       sprintf(wname, "TAKE-%d", takeId);
+
+       w->pathfile = gGetCurrentPath()+"/"+wname; // FIXME - use gGetSlash() in utils.h
+       w->name     = wname;
+       wave        = w;
+       status      = STATUS_OFF;
+       begin       = 0;
+       end         = wave->size;
+
+       sendMidiLplay();
+
+       return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::process(float *buffer)
+{
+#ifdef WITH_VST
+       G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
+#endif
+
+       for (int j=0; j<bufferSize; j+=2) {
+               buffer[j]   += vChan[j]   * volume * panLeft  * boost;
+               buffer[j+1] += vChan[j+1] * volume * panRight * boost;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::kill(int frame)
+{
+       if (wave != NULL && status != STATUS_OFF) {
+               if (mute || mute_i || (status == STATUS_WAIT && mode & LOOP_ANY))
+                       hardStop(frame);
+               else
+                       setFadeOut(DO_STOP);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::stopBySeq()
+{
+       /* kill loop channels and recs if "samplesStopOnSeqHalt" == true,
+        * else do nothing and return. Always kill at frame=0, this is a
+        * user-generated event. */
+
+       if (!G_Conf.chansStopOnSeqHalt)
+               return;
+
+       if (mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT))
+               kill(0);
+
+       /** FIXME - merge these */
+
+       /* when a channel has recs in play?
+        * Recorder has events for that channel
+        * G_Mixer has at least one sample in play
+        * Recorder's channel is active (altrimenti può capitare che
+        * si stoppino i sample suonati manualmente in un canale con rec
+        * disattivate) */
+
+       if (hasActions && readActions && status == STATUS_PLAY)
+               kill(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::stop()
+{
+       if (mode == SINGLE_PRESS && status == STATUS_PLAY) {
+               if (mute || mute_i)
+                       hardStop(0);  /// FIXME - wrong frame value
+               else
+                       setFadeOut(DO_STOP);
+       }
+       else  // stop a SINGLE_PRESS immediately, if the quantizer is on
+       if (mode == SINGLE_PRESS && qWait == true)
+               qWait = false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int SampleChannel::load(const char *file)
+{
+       if (strcmp(file, "") == 0 || gIsDir(file)) {
+               gLog("[SampleChannel] file not specified\n");
+               return SAMPLE_LEFT_EMPTY;
+       }
+
+       if (strlen(file) > FILENAME_MAX)
+               return SAMPLE_PATH_TOO_LONG;
+
+       Wave *w = new Wave();
+
+       if (!w->open(file)) {
+               gLog("[SampleChannel] %s: read error\n", file);
+               delete w;
+               return SAMPLE_READ_ERROR;
+       }
+
+       if (w->channels() > 2) {
+               gLog("[SampleChannel] %s: unsupported multichannel wave\n", file);
+               delete w;
+               return SAMPLE_MULTICHANNEL;
+       }
+
+       if (!w->readData()) {
+               delete w;
+               return SAMPLE_READ_ERROR;
+       }
+
+       if (w->channels() == 1) /** FIXME: error checking  */
+               wfx_monoToStereo(w);
+
+       if (w->rate() != G_Conf.samplerate) {
+               gLog("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n",
+                               w->rate(), G_Conf.samplerate);
+               w->resample(G_Conf.rsmpQuality, G_Conf.samplerate);
+       }
+
+       pushWave(w);
+
+       /* sample name must be unique. Start from k = 1, zero is too nerdy */
+
+       std::string oldName = wave->name;
+       int k = 1;
+       while (!mh_uniqueSamplename(this, wave->name.c_str())) {
+               wave->updateName((oldName + "-" + gItoa(k)).c_str());
+               k++;
+       }
+
+       gLog("[SampleChannel] %s loaded in channel %d\n", file, index);
+       return SAMPLE_LOADED_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int SampleChannel::loadByPatch(const char *f, int i)
+{
+       int res = load(f);
+
+               volume      = G_Patch.getVol(i);
+               key         = G_Patch.getKey(i);
+               index       = G_Patch.getIndex(i);
+               mode        = G_Patch.getMode(i);
+               mute        = G_Patch.getMute(i);
+               mute_s      = G_Patch.getMute_s(i);
+               solo        = G_Patch.getSolo(i);
+               boost       = G_Patch.getBoost(i);
+               panLeft     = G_Patch.getPanLeft(i);
+               panRight    = G_Patch.getPanRight(i);
+               readActions = G_Patch.getRecActive(i);
+               recStatus   = readActions ? REC_READING : REC_STOPPED;
+
+               readPatchMidiIn(i);
+               midiInReadActions = G_Patch.getMidiValue(i, "InReadActions");
+               midiInPitch       = G_Patch.getMidiValue(i, "InPitch");
+               readPatchMidiOut(i);
+
+       if (res == SAMPLE_LOADED_OK) {
+               setBegin(G_Patch.getBegin(i));
+               setEnd  (G_Patch.getEnd(i, wave->size));
+               setPitch(G_Patch.getPitch(i));
+       }
+       else {
+               // volume = DEFAULT_VOL;
+               // mode   = DEFAULT_CHANMODE;
+               // status = STATUS_WRONG;
+               // key    = 0;
+
+               if (res == SAMPLE_LEFT_EMPTY)
+                       status = STATUS_EMPTY;
+               else
+               if (res == SAMPLE_READ_ERROR)
+                       status = STATUS_MISSING;
+               sendMidiLplay();
+       }
+
+       return res;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool SampleChannel::canInputRec()
+       {
+       return wave == NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::start(int frame, bool doQuantize)
+{
+       switch (status) {
+               case STATUS_EMPTY:
+               case STATUS_MISSING:
+               case STATUS_WRONG:
+               {
+                       return;
+               }
+
+               case STATUS_OFF:
+               {
+                       if (mode & LOOP_ANY) {
+                               status = STATUS_WAIT;
+                               sendMidiLplay();
+                       }
+                       else {
+                               if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
+                                       qWait = true;
+                               else {
+
+                                       /* fillChan only if frame != 0. If you call fillChan on frame == 0
+                                        * a duplicate call to fillChan occurs with loss of data. */
+
+                                       status = STATUS_PLAY;
+                                       sendMidiLplay();
+                                       if (frame != 0)
+                                               tracker = fillChan(vChan, tracker, frame);
+                               }
+                       }
+                       break;
+               }
+
+               case STATUS_PLAY:
+               {
+                       if (mode == SINGLE_BASIC)
+                               setFadeOut(DO_STOP);
+                       else
+                       if (mode == SINGLE_RETRIG) {
+                               if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
+                                       qWait = true;
+                               else
+                                       reset(frame);
+                       }
+                       else
+                       if (mode & (LOOP_ANY | SINGLE_ENDLESS)) {
+                               status = STATUS_ENDING;
+                               sendMidiLplay();
+                       }
+                       break;
+               }
+
+               case STATUS_WAIT:
+               {
+                       status = STATUS_OFF;
+                       sendMidiLplay();
+                       break;
+               }
+
+               case STATUS_ENDING:
+               {
+                       status = STATUS_PLAY;
+                       sendMidiLplay();
+                       break;
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::writePatch(FILE *fp, int i, bool isProject)
+{
+       Channel::writePatch(fp, i, isProject);
+
+       const char *path = "";
+       if (wave != NULL) {
+               path = wave->pathfile.c_str();
+               if (isProject)
+                       path = gBasename(path).c_str();  // make it portable
+       }
+
+       fprintf(fp, "samplepath%d=%s\n",     i, path);
+       fprintf(fp, "chanKey%d=%d\n",        i, key);
+       //fprintf(fp, "columnIndex%d=%d\n",    i, index);
+       fprintf(fp, "chanmode%d=%d\n",       i, mode);
+       fprintf(fp, "chanBegin%d=%d\n",      i, begin);
+       fprintf(fp, "chanend%d=%d\n",        i, end);
+       fprintf(fp, "chanBoost%d=%f\n",      i, boost);
+       fprintf(fp, "chanRecActive%d=%d\n",  i, readActions);
+       fprintf(fp, "chanPitch%d=%f\n",      i, pitch);
+
+       fprintf(fp, "chanMidiInReadActions%d=%u\n", i, midiInReadActions);
+       fprintf(fp, "chanMidiInPitch%d=%u\n",       i, midiInPitch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::clearChan(float *dest, int start)
+{
+       memset(dest+start, 0, sizeof(float)*(bufferSize-start));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind)
+{
+       int position;  // return value: the new position
+
+       if (pitch == 1.0f) {
+
+               /* case 1: 'dest' lies within the original sample boundaries (start-
+                * end) */
+
+               if (start+bufferSize-offset <= end) {
+                       memcpy(dest+offset, wave->data+start, (bufferSize-offset)*sizeof(float));
+                       position = start+bufferSize-offset;
+                       if (rewind)
+                               frameRewind = -1;
+               }
+
+               /* case2: 'dest' lies outside the end of the sample, OR the sample
+                * is smaller than 'dest' */
+
+               else {
+                       memcpy(dest+offset, wave->data+start, (end-start)*sizeof(float));
+                       position = end;
+                       if (rewind)
+                               frameRewind = end-start+offset;
+               }
+       }
+       else {
+
+               rsmp_data.data_in       = wave->data+start;         // source data
+               rsmp_data.input_frames  = (end-start)/2;            // how many readable bytes
+               rsmp_data.data_out      = dest+offset;              // destination (processed data)
+               rsmp_data.output_frames = (bufferSize-offset)/2;    // how many bytes to process
+               rsmp_data.end_of_input  = false;
+
+               src_process(rsmp_state, &rsmp_data);
+               int gen = rsmp_data.output_frames_gen*2;            // frames generated by this call
+
+               position = start + rsmp_data.input_frames_used*2;   // position goes forward of frames_used (i.e. read from wave)
+
+               if (rewind) {
+                       if (gen == bufferSize-offset)
+                               frameRewind = -1;
+                       else
+                               frameRewind = gen+offset;
+               }
+       }
+       return position;
+}
diff --git a/src/core/sampleChannel.h b/src/core/sampleChannel.h
new file mode 100644 (file)
index 0000000..736063a
--- /dev/null
@@ -0,0 +1,210 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * sampleChannel
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef SAMPLE_CHANNEL_H
+#define SAMPLE_CHANNEL_H
+
+
+#include <samplerate.h>
+#include "channel.h"
+
+
+class SampleChannel : public Channel {
+
+private:
+
+       /* rsmp_state, rsmp_data
+        * structs from libsamplerate */
+
+       SRC_STATE *rsmp_state;
+       SRC_DATA   rsmp_data;
+
+       /* pChan
+        * extra virtual channel for processing resampled data.  */
+
+       float *pChan;
+
+       /* frameRewind
+        * exact frame in which a rewind occurs */
+
+       int frameRewind;
+
+       /* fillChan
+        * copy from wave to *dest and resample data from wave, if necessary.
+        * Start to fill pChan from byte 'offset'. If rewind=false don't
+        * rewind internal tracker. Returns new sample position, in frames */
+
+       int fillChan(float *dest, int start, int offset, bool rewind=true);
+
+       /* clearChan
+        * set data to zero from start to bufferSize-1. */
+
+       void clearChan(float *dest, int start);
+
+       /* calcFadeoutStep
+        * how many frames are left before the end of the sample? Is there
+        * enough room for a complete fadeout? Should we shorten it? */
+
+       void calcFadeoutStep();
+
+       /* calcVolumeEnv
+        * compute any changes in volume done via envelope tool */
+
+       void calcVolumeEnv(int frame);
+
+public:
+
+       SampleChannel(int bufferSize);
+       ~SampleChannel();
+
+       void  clear      ();
+       void  process    (float *buffer);
+       void  start      (int frame, bool doQuantize);
+       void  kill       (int frame);
+       void  empty      ();
+       void  stopBySeq  ();
+       void  stop       ();
+       void  rewind     ();
+       void  setMute    (bool internal);
+       void  unsetMute  (bool internal);
+       void  reset      (int frame);
+       int   load       (const char *file);
+       int   loadByPatch(const char *file, int i);
+       void  writePatch (FILE *fp, int i, bool isProject);
+       void  quantize   (int index, int localFrame, int globalFrame);
+       void  onZero     (int frame);
+       void  onBar      (int frame);
+       void  parseAction(recorder::action *a, int localFrame, int globalFrame);
+
+       /* fade methods
+        * prepare channel for fade, mixer will take care of the process
+        * during master play. */
+
+       void  setFadeIn  (bool internal);
+       void  setFadeOut (int actionPostFadeout);
+       void  setXFade   (int frame);
+
+       /* pushWave
+        * add a new wave to an existing channel. */
+
+       void pushWave(class Wave *w);
+
+       /* getPosition
+        * returns the position of an active sample. If EMPTY o MISSING
+        * returns -1. */
+
+       int getPosition();
+
+       /* sum
+        * add sample frames to virtual channel. Frame = processed frame in
+        * Mixer. Running = is Mixer in play? */
+
+       void sum(int frame, bool running);
+
+       /* setPitch
+        * updates the pitch value and chanStart+chanEnd accordingly. */
+
+       void setPitch(float v);
+
+       /* setStart/end
+        * change begin/end read points in sample. */
+
+       void setBegin(unsigned v);
+       void setEnd  (unsigned v);
+
+       /* save
+        * save sample to file. */
+
+       int save(const char *path);
+
+       /* hardStop
+        * stop the channel immediately, no further checks. */
+
+       void hardStop(int frame);
+
+       /* allocEmpty
+        * alloc an empty wave used in input recordings. */
+
+       bool allocEmpty(int frames, int takeId);
+
+       /* canInputRec
+        * true if channel can host a new wave from input recording. */
+
+       bool  canInputRec();
+
+       /* setReadActions
+        * if enabled, recorder will read actions from this channel */
+
+       void setReadActions(bool v);
+
+       /* ---------------------------------------------------------------- */
+
+       class  Wave *wave;
+       int    tracker;         // chan position
+       int    begin;
+       int    end;
+  float  pitch;
+       float  boost;
+       int    mode;            // mode: see const.h
+       bool   qWait;           // quantizer wait
+       bool   fadeinOn;
+       float  fadeinVol;
+       bool   fadeoutOn;
+       float  fadeoutVol;      // fadeout volume
+       int    fadeoutTracker;  // tracker fadeout, xfade only
+       float  fadeoutStep;     // fadeout decrease
+  int    fadeoutType;     // xfade or fadeout
+  int           fadeoutEnd;      // what to do when fadeout ends
+
+       /* recorder:: stuff */
+
+  bool   readActions;     // read actions or not
+
+       /* midi stuff */
+
+  uint32_t midiInReadActions;
+  uint32_t midiInPitch;
+
+       /* const - what to do when a fadeout ends */
+
+       enum {
+               DO_STOP   = 0x01,
+               DO_MUTE   = 0x02,
+               DO_MUTE_I = 0x04
+       };
+
+       /*  const - fade types */
+
+       enum {
+               FADEOUT = 0x01,
+               XFADE   = 0x02
+       };
+};
+
+#endif
diff --git a/src/core/wave.cpp b/src/core/wave.cpp
new file mode 100644 (file)
index 0000000..ee81c6d
--- /dev/null
@@ -0,0 +1,245 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * wave
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>  // memcpy
+#include <math.h>
+#include "../utils/utils.h"
+#include "../utils/log.h"
+#include "wave.h"
+#include "conf.h"
+#include "init.h"
+
+
+extern Conf G_Conf;
+
+
+Wave::Wave()
+       : data     (NULL),
+               size     (0),
+               isLogical(0),
+               isEdited (0) {}
+
+
+/* ------------------------------------------------------------------ */
+
+
+Wave::~Wave() {
+       clear();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Wave::open(const char *f) {
+
+       pathfile = f;
+       name     = gStripExt(gBasename(f).c_str());
+       fileIn   = sf_open(f, SFM_READ, &inHeader);
+
+       if (fileIn == NULL) {
+               gLog("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn));
+               pathfile = "";
+               name     = "";
+               return 0;
+       }
+
+       isLogical = false;
+       isEdited  = false;
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+/* how to read and write with libsndfile:
+ *
+ * a frame consists of all items (samples) that belong to the same
+ * point in time. So in each frame there are as many items as there
+ * are channels.
+ *
+ * Quindi:
+ *     frame  = [item, item, ...]
+ * In pratica:
+ *  frame1 = [itemLeft, itemRight]
+ *     frame2 = [itemLeft, itemRight]
+ *     ...
+ */
+
+int Wave::readData() {
+       size = inHeader.frames * inHeader.channels;
+       data = (float *) malloc(size * sizeof(float));
+       if (data == NULL) {
+               gLog("[wave] unable to allocate memory\n");
+               return 0;
+       }
+
+       if (sf_read_float(fileIn, data, size) != size)
+               gLog("[wave] warning: incomplete read!\n");
+
+       sf_close(fileIn);
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Wave::writeData(const char *f) {
+
+       /* prepare the header for output file */
+
+       outHeader.samplerate = inHeader.samplerate;
+       outHeader.channels   = inHeader.channels;
+       outHeader.format     = inHeader.format;
+
+       fileOut = sf_open(f, SFM_WRITE, &outHeader);
+       if (fileOut == NULL) {
+               gLog("[wave] unable to open %s for exporting\n", f);
+               return 0;
+       }
+
+       int out = sf_write_float(fileOut, data, size);
+       if (out != (int) size) {
+               gLog("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut));
+               return 0;
+       }
+
+       isLogical = false;
+       isEdited  = false;
+       sf_close(fileOut);
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Wave::clear() {
+       if (data != NULL) {
+               free(data);
+               data     = NULL;
+               pathfile = "";
+               size     = 0;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Wave::allocEmpty(unsigned __size) {
+
+       /* the caller must pass a __size for stereo values */
+
+       /// FIXME - this way if malloc fails size becomes wrong
+       size = __size;
+       data = (float *) malloc(size * sizeof(float));
+       if (data == NULL) {
+               gLog("[wave] unable to allocate memory\n");
+               return 0;
+       }
+
+       memset(data, 0, sizeof(float) * size); /// FIXME - is it useful?
+
+       inHeader.samplerate = G_Conf.samplerate;
+       inHeader.channels   = 2;
+       inHeader.format     = SF_FORMAT_WAV | SF_FORMAT_FLOAT; // wave only
+
+       isLogical = true;
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int Wave::resample(int quality, int newRate) {
+
+       float ratio = newRate / (float) inHeader.samplerate;
+       int newSize = ceil(size * ratio);
+       if (newSize % 2 != 0)   // libsndfile goes crazy with odd size in case of saving
+               newSize++;
+
+       float *tmp = (float *) malloc(newSize * sizeof(float));
+       if (!tmp) {
+               gLog("[wave] unable to allocate memory for resampling\n");
+               return -1;
+       }
+
+       SRC_DATA src_data;
+       src_data.data_in       = data;
+       src_data.input_frames  = size/2;     // in frames, i.e. /2 (stereo)
+       src_data.data_out      = tmp;
+       src_data.output_frames = newSize/2;  // in frames, i.e. /2 (stereo)
+       src_data.src_ratio     = ratio;
+
+       gLog("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2);
+
+       int ret = src_simple(&src_data, quality, 2);
+       if (ret != 0) {
+               gLog("[wave] resampling error: %s\n", src_strerror(ret));
+               return 0;
+       }
+
+       free(data);
+       data = tmp;
+       size = newSize;
+       inHeader.samplerate = newRate;
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+std::string Wave::basename() {
+       return gStripExt(gBasename(pathfile.c_str()).c_str());
+}
+
+std::string Wave::extension() {
+       return gGetExt(pathfile.c_str());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Wave::updateName(const char *n) {
+       std::string ext = gGetExt(pathfile.c_str());
+       name      = gStripExt(gBasename(n).c_str());
+       pathfile  = gDirname(pathfile.c_str()) + gGetSlash() + name + "." + ext;
+       isLogical = true;
+
+       /* a wave with updated name must become logical, since the underlying
+        * file does not exist yet. */
+}
diff --git a/src/core/wave.h b/src/core/wave.h
new file mode 100644 (file)
index 0000000..9ce81df
--- /dev/null
@@ -0,0 +1,88 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * wave
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef WAVE_H
+#define WAVE_H
+
+
+#include <samplerate.h>
+#include <sndfile.h>
+#include <string>
+
+
+class Wave {
+
+private:
+
+       SNDFILE   *fileIn;
+       SNDFILE   *fileOut;
+       SF_INFO    inHeader;
+       SF_INFO    outHeader;
+
+public:
+
+       Wave();
+       ~Wave();
+
+       std::string pathfile; // full path + sample name
+       std::string name;                       // sample name (changeable)
+
+       float     *data;
+       int        size;                          // wave size (size in stereo: size / 2)
+       bool       isLogical;   // memory only (a take)
+       bool       isEdited;    // edited via editor
+
+       inline int  rate    () { return inHeader.samplerate; }
+       inline int  channels() { return inHeader.channels; }
+       inline int  frames  () { return inHeader.frames; }
+       inline void rate    (int v) { inHeader.samplerate = v; }
+       inline void channels(int v) { inHeader.channels = v; }
+       inline void frames  (int v) { inHeader.frames = v; }
+
+       std::string basename ();
+       std::string extension();
+
+       void updateName(const char *n);
+       int  open      (const char *f);
+       int  readData  ();
+       int      writeData (const char *f);
+       void clear     ();
+
+       /* allocEmpty
+        * alloc an empty waveform. */
+
+       int allocEmpty(unsigned size);
+
+       /* resample
+        * simple algorithm for one-shot resampling. */
+
+       int resample(int quality, int newRate);
+};
+
+#endif
diff --git a/src/core/waveFx.cpp b/src/core/waveFx.cpp
new file mode 100644 (file)
index 0000000..368bd79
--- /dev/null
@@ -0,0 +1,224 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * waveFx
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <math.h>
+#include "../utils/log.h"
+#include "waveFx.h"
+#include "channel.h"
+#include "mixer.h"
+#include "wave.h"
+
+
+extern Mixer G_Mixer;
+
+
+float wfx_normalizeSoft(Wave *w) {
+       float peak = 0.0f;
+       float abs  = 0.0f;
+       for (int i=0; i<w->size; i++) { // i++: both L and R samples
+               abs = fabs(w->data[i]);
+               if (abs > peak)
+                       peak = abs;
+       }
+
+       /* peak == 0.0f: don't normalize the silence
+        * peak > 1.0f: don't reduce the amplitude, just leave it alone */
+
+       if (peak == 0.0f || peak > 1.0f)
+               return 1.0f;
+
+       return 1.0f / peak;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool wfx_monoToStereo(Wave *w) {
+
+       unsigned newSize = w->size * 2;
+       float *dataNew = (float *) malloc(newSize * sizeof(float));
+       if (dataNew == NULL) {
+               gLog("[wfx] unable to allocate memory for mono>stereo conversion\n");
+               return 0;
+       }
+
+       for (int i=0, j=0; i<w->size; i++) {
+               dataNew[j]   = w->data[i];
+               dataNew[j+1] = w->data[i];
+               j+=2;
+       }
+
+       free(w->data);
+       w->data = dataNew;
+       w->size = newSize;
+       w->frames(w->frames()*2);
+       w->channels(2);
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void wfx_silence(Wave *w, int a, int b) {
+
+       /* stereo values */
+       a = a * 2;
+       b = b * 2;
+
+       gLog("[wfx] silencing from %d to %d\n", a, b);
+
+       for (int i=a; i<b; i+=2) {
+               w->data[i]   = 0.0f;
+               w->data[i+1] = 0.0f;
+       }
+
+       w->isEdited = true;
+
+       return;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int wfx_cut(Wave *w, int a, int b) {
+       a = a * 2;
+       b = b * 2;
+
+       if (a < 0) a = 0;
+       if (b > w->size) b = w->size;
+
+       /* create a new temp wave and copy there the original one, skipping
+        * the a-b range */
+
+       unsigned newSize = w->size-(b-a);
+       float *temp = (float *) malloc(newSize * sizeof(float));
+       if (temp == NULL) {
+               gLog("[wfx] unable to allocate memory for cutting\n");
+               return 0;
+       }
+
+       gLog("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2);
+
+       for (int i=0, k=0; i<w->size; i++) {
+               if (i < a || i >= b) {                         // left margin always included, in order to keep
+                       temp[k] = w->data[i];   // the stereo pair
+                       k++;
+               }
+       }
+
+       free(w->data);
+       w->data = temp;
+       w->size = newSize;
+       //w->inHeader.frames -= b-a;
+       w->frames(w->frames() - b - a);
+       w->isEdited = true;
+
+       gLog("[wfx] cutting done\n");
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int wfx_trim(Wave *w, int a, int b) {
+       a = a * 2;
+       b = b * 2;
+
+       if (a < 0) a = 0;
+       if (b > w->size) b = w->size;
+
+       int newSize = b - a;
+       float *temp = (float *) malloc(newSize * sizeof(float));
+       if (temp == NULL) {
+               gLog("[wfx] unable to allocate memory for trimming\n");
+               return 0;
+       }
+
+       gLog("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a);
+
+       for (int i=a, k=0; i<b; i++, k++)
+               temp[k] = w->data[i];
+
+       free(w->data);
+       w->data = temp;
+       w->size = newSize;
+       //w->inHeader.frames = b-a;
+       w->frames(b - a);
+       w->isEdited = true;
+
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void wfx_fade(Wave *w, int a, int b, int type) {
+
+       float m = type == 0 ? 0.0f : 1.0f;
+       float d = 1.0f/(float)(b-a);
+       if (type == 1)
+               d = -d;
+
+       a *= 2;
+       b *= 2;
+
+       for (int i=a; i<b; i+=2) {
+               w->data[i]   *= m;
+               w->data[i+1] *= m;
+               m += d;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void wfx_smooth(Wave *w, int a, int b) {
+
+       int d = 32;  // 64 if stereo data
+
+       /* do nothing if fade edges (both of 32 samples) are > than selected
+        * portion of wave. d*2 => count both edges, (b-a)*2 => stereo
+        * values. */
+
+       if (d*2 > (b-a)*2) {
+               gLog("[WFX] selection is too small, nothing to do\n");
+               return;
+       }
+
+       wfx_fade(w, a, a+d, 0);
+       wfx_fade(w, b-d, b, 1);
+}
diff --git a/src/core/waveFx.h b/src/core/waveFx.h
new file mode 100644 (file)
index 0000000..ebdef4a
--- /dev/null
@@ -0,0 +1,59 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * waveFx
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef WAVEFX_H
+#define WAVEFX_H
+
+
+/* normalizeSoft
+ * normalize the wave by returning the dB value for the boost volume. It
+ * doesn't deal with data in memory. */
+
+float wfx_normalizeSoft(class Wave *w);
+
+bool wfx_monoToStereo(class Wave *w);
+
+void wfx_silence(class Wave *w, int a, int b);
+
+int wfx_cut(class Wave *w, int a, int b);
+
+int wfx_trim(class Wave *w, int a, int b);
+
+/* fade
+ * fade in or fade out selection. Fade In = type 0, Fade Out = type 1 */
+
+void wfx_fade(class Wave *w, int a, int b, int type);
+
+/* smooth
+ * smooth edges of selection. */
+
+void wfx_smooth(class Wave *w, int a, int b);
+
+
+#endif
diff --git a/src/dataStorage.cpp b/src/dataStorage.cpp
deleted file mode 100644 (file)
index 43729e8..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * dataStorage
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdlib.h>
-#include <limits.h>
-#include "dataStorage.h"
-#include "const.h"
-#include "log.h"
-
-
-std::string DataStorage::getValue(const char *in) {
-
-       /* on each call reset the pointe to the beginning of the file. Not so
-        * good but necessary if you want to pick up random values from the
-        * file. */
-
-       fseek(fp, 0L, SEEK_SET);
-       std::string out = "";
-
-       while (!feof(fp)) {
-
-               char buffer[MAX_LINE_LEN];
-               if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) {
-                       gLog("[PATCH] get_value error (key=%s)\n", in);
-                       return "";
-               }
-
-               if (buffer[0] == '#')
-                       continue;
-
-               unsigned len = strlen(in);
-               if (strncmp(buffer, in, len) == 0) {
-
-                       for (unsigned i=len+1; i<MAX_LINE_LEN; i++) {
-                               if (buffer[i] == '\0' || buffer[i] == '\n' || buffer[i] == '\r')
-                                       break;
-                               out += buffer[i];
-                       }
-
-                       break; // string found
-               }
-       }
-       return out;
-}
diff --git a/src/dataStorage.h b/src/dataStorage.h
deleted file mode 100644 (file)
index 9d54ddf..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * dataStorage
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __DATA_STORAGE_H__
-#define __DATA_STORAGE_H__
-
-#include <stdio.h>
-#include <string>
-#include <string.h>
-
-#define MAX_LINE_LEN 1024
-
-
-class DataStorage {
-
-protected:
-
-       FILE *fp;
-       std::string getValue(const char *in);
-};
-
-#endif
diff --git a/src/deps/rtaudio-mod/Makefile.in b/src/deps/rtaudio-mod/Makefile.in
new file mode 100644 (file)
index 0000000..89cacdc
--- /dev/null
@@ -0,0 +1,75 @@
+### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in
+### RtAudio library Makefile
+
+RM = /bin/rm
+LN = /bin/ln
+
+OBJECTS        = RtAudio.o @objects@
+
+LIBNAME = librtaudio
+STATIC = $(LIBNAME).a
+SHARED = @sharedlib@
+RELEASE = 4.1.1
+MAJOR = 4
+LIBRARIES = $(STATIC) $(SHARED)
+
+CC       = @CXX@
+AR       = @AR@
+RANLIB   = @RANLIB@
+
+DEFS     = @CPPFLAGS@
+CFLAGS   = @CXXFLAGS@ -Iinclude -fPIC
+
+PREFIX   = @prefix@
+
+all : $(LIBRARIES)
+
+tests:
+       cd tests && $(MAKE) all
+
+$(LIBRARIES): $(OBJECTS)
+       $(AR) ruv $(STATIC) $(OBJECTS)
+       ranlib $(STATIC)
+       $(CC) -fPIC @libflags@ $(OBJECTS) @LIBS@
+       $(LN) -sf @sharedname@ $(SHARED)
+       $(LN) -sf @sharedname@ $(SHARED).$(MAJOR)
+
+%.o : %.cpp
+       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
+
+%.o : include/%.cpp
+       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
+
+install:
+       install --mode=755 $(STATIC) $(PREFIX)/lib/
+       install --mode=755 @sharedname@ $(PREFIX)/lib/
+       $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED)
+       $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED).$(MAJOR)
+       install --mode=644 $(LIBNAME).pc $(PREFIX)/lib/pkgconfig
+       install --mode=644 RtAudio.h $(PREFIX)/include/
+       install --mode=755 rtaudio-config $(PREFIX)/bin/
+
+uninstall:
+       -@rm -vf $(patsubst %,$(PREFIX)/lib/%, $(LIBRARIES) $(SHARED).$(MAJOR) $(SHARED).$(RELEASE))
+       -@rm -vf $(PREFIX)/lib/pkgconfig/$(LIBNAME).pc
+       -@rm -vf $(PREFIX)/bin/rtaudio-config
+
+clean : 
+       $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
+       $(RM) -f $(OBJECTS)
+       $(RM) -f *~
+       cd tests && $(MAKE) clean
+
+distclean:
+       $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
+       $(RM) -f $(OBJECTS)
+       $(RM) -f *~
+       $(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config $(LIBNAME).pc
+       cd tests && $(MAKE) distclean
+
+strip : 
+       strip $(LIBRARIES)
+       ranlib $(LIBRARIES)
+       cd tests && $(MAKE) strip
+
+.PHONY: clean distclean strip install uninstall
diff --git a/src/deps/rtaudio-mod/RtAudio.cpp b/src/deps/rtaudio-mod/RtAudio.cpp
new file mode 100644 (file)
index 0000000..5716c59
--- /dev/null
@@ -0,0 +1,10145 @@
+/************************************************************************/\r
+/*! \class RtAudio\r
+    \brief Realtime audio i/o C++ classes.\r
+\r
+    RtAudio provides a common API (Application Programming Interface)\r
+    for realtime audio input/output across Linux (native ALSA, Jack,\r
+    and OSS), Macintosh OS X (CoreAudio and Jack), and Windows\r
+    (DirectSound, ASIO and WASAPI) operating systems.\r
+\r
+    RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
+\r
+    RtAudio: realtime audio i/o C++ classes\r
+    Copyright (c) 2001-2014 Gary P. Scavone\r
+\r
+    Permission is hereby granted, free of charge, to any person\r
+    obtaining a copy of this software and associated documentation files\r
+    (the "Software"), to deal in the Software without restriction,\r
+    including without limitation the rights to use, copy, modify, merge,\r
+    publish, distribute, sublicense, and/or sell copies of the Software,\r
+    and to permit persons to whom the Software is furnished to do so,\r
+    subject to the following conditions:\r
+\r
+    The above copyright notice and this permission notice shall be\r
+    included in all copies or substantial portions of the Software.\r
+\r
+    Any person wishing to distribute modifications to the Software is\r
+    asked to send the modifications to the original developer so that\r
+    they can be incorporated into the canonical version.  This is,\r
+    however, not a binding provision of this license.\r
+\r
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+*/\r
+/************************************************************************/\r
+\r
+// RtAudio: Version 4.1.1\r
+\r
+#include "RtAudio.h"\r
+#include <iostream>\r
+#include <cstdlib>\r
+#include <cstring>\r
+#include <climits>\r
+\r
+// Static variable definitions.\r
+const unsigned int RtApi::MAX_SAMPLE_RATES = 14;\r
+const unsigned int RtApi::SAMPLE_RATES[] = {\r
+  4000, 5512, 8000, 9600, 11025, 16000, 22050,\r
+  32000, 44100, 48000, 88200, 96000, 176400, 192000\r
+};\r
+\r
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)\r
+  #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)\r
+  #define MUTEX_DESTROY(A)    DeleteCriticalSection(A)\r
+  #define MUTEX_LOCK(A)       EnterCriticalSection(A)\r
+  #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)\r
+#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)\r
+  // pthread API\r
+  #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)\r
+  #define MUTEX_DESTROY(A)    pthread_mutex_destroy(A)\r
+  #define MUTEX_LOCK(A)       pthread_mutex_lock(A)\r
+  #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)\r
+#else\r
+  #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions\r
+  #define MUTEX_DESTROY(A)    abs(*A) // dummy definitions\r
+#endif\r
+\r
+// *************************************************** //\r
+//\r
+// RtAudio definitions.\r
+//\r
+// *************************************************** //\r
+\r
+std::string RtAudio :: getVersion( void ) throw()\r
+{\r
+  return RTAUDIO_VERSION;\r
+}\r
+\r
+void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()\r
+{\r
+  apis.clear();\r
+\r
+  // The order here will control the order of RtAudio's API search in\r
+  // the constructor.\r
+#if defined(__UNIX_JACK__)\r
+  apis.push_back( UNIX_JACK );\r
+#endif\r
+#if defined(__LINUX_ALSA__)\r
+  apis.push_back( LINUX_ALSA );\r
+#endif\r
+#if defined(__LINUX_PULSE__)\r
+  apis.push_back( LINUX_PULSE );\r
+#endif\r
+#if defined(__LINUX_OSS__)\r
+  apis.push_back( LINUX_OSS );\r
+#endif\r
+#if defined(__WINDOWS_ASIO__)\r
+  apis.push_back( WINDOWS_ASIO );\r
+#endif\r
+#if defined(__WINDOWS_WASAPI__)\r
+  apis.push_back( WINDOWS_WASAPI );\r
+#endif\r
+#if defined(__WINDOWS_DS__)\r
+  apis.push_back( WINDOWS_DS );\r
+#endif\r
+#if defined(__MACOSX_CORE__)\r
+  apis.push_back( MACOSX_CORE );\r
+#endif\r
+#if defined(__RTAUDIO_DUMMY__)\r
+  apis.push_back( RTAUDIO_DUMMY );\r
+#endif\r
+}\r
+\r
+void RtAudio :: openRtApi( RtAudio::Api api )\r
+{\r
+  if ( rtapi_ )\r
+    delete rtapi_;\r
+  rtapi_ = 0;\r
+\r
+#if defined(__UNIX_JACK__)\r
+  if ( api == UNIX_JACK )\r
+    rtapi_ = new RtApiJack();\r
+#endif\r
+#if defined(__LINUX_ALSA__)\r
+  if ( api == LINUX_ALSA )\r
+    rtapi_ = new RtApiAlsa();\r
+#endif\r
+#if defined(__LINUX_PULSE__)\r
+  if ( api == LINUX_PULSE )\r
+    rtapi_ = new RtApiPulse();\r
+#endif\r
+#if defined(__LINUX_OSS__)\r
+  if ( api == LINUX_OSS )\r
+    rtapi_ = new RtApiOss();\r
+#endif\r
+#if defined(__WINDOWS_ASIO__)\r
+  if ( api == WINDOWS_ASIO )\r
+    rtapi_ = new RtApiAsio();\r
+#endif\r
+#if defined(__WINDOWS_WASAPI__)\r
+  if ( api == WINDOWS_WASAPI )\r
+    rtapi_ = new RtApiWasapi();\r
+#endif\r
+#if defined(__WINDOWS_DS__)\r
+  if ( api == WINDOWS_DS )\r
+    rtapi_ = new RtApiDs();\r
+#endif\r
+#if defined(__MACOSX_CORE__)\r
+  if ( api == MACOSX_CORE )\r
+    rtapi_ = new RtApiCore();\r
+#endif\r
+#if defined(__RTAUDIO_DUMMY__)\r
+  if ( api == RTAUDIO_DUMMY )\r
+    rtapi_ = new RtApiDummy();\r
+#endif\r
+}\r
+\r
+RtAudio :: RtAudio( RtAudio::Api api )\r
+{\r
+  rtapi_ = 0;\r
+\r
+  if ( api != UNSPECIFIED ) {\r
+    // Attempt to open the specified API.\r
+    openRtApi( api );\r
+    if ( rtapi_ ) return;\r
+\r
+    // No compiled support for specified API value.  Issue a debug\r
+    // warning and continue as if no API was specified.\r
+    std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;\r
+  }\r
+\r
+  // Iterate through the compiled APIs and return as soon as we find\r
+  // one with at least one device or we reach the end of the list.\r
+  std::vector< RtAudio::Api > apis;\r
+  getCompiledApi( apis );\r
+  for ( unsigned int i=0; i<apis.size(); i++ ) {\r
+    openRtApi( apis[i] );\r
+    if ( rtapi_->getDeviceCount() ) break;\r
+  }\r
+\r
+  if ( rtapi_ ) return;\r
+\r
+  // It should not be possible to get here because the preprocessor\r
+  // definition __RTAUDIO_DUMMY__ is automatically defined if no\r
+  // API-specific definitions are passed to the compiler. But just in\r
+  // case something weird happens, we'll thow an error.\r
+  std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";\r
+  throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );\r
+}\r
+\r
+RtAudio :: ~RtAudio() throw()\r
+{\r
+  if ( rtapi_ )\r
+    delete rtapi_;\r
+}\r
+\r
+void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,\r
+                            RtAudio::StreamParameters *inputParameters,\r
+                            RtAudioFormat format, unsigned int sampleRate,\r
+                            unsigned int *bufferFrames,\r
+                            RtAudioCallback callback, void *userData,\r
+                            RtAudio::StreamOptions *options,\r
+                            RtAudioErrorCallback errorCallback )\r
+{\r
+  return rtapi_->openStream( outputParameters, inputParameters, format,\r
+                             sampleRate, bufferFrames, callback,\r
+                             userData, options, errorCallback );\r
+}\r
+\r
+// *************************************************** //\r
+//\r
+// Public RtApi definitions (see end of file for\r
+// private or protected utility functions).\r
+//\r
+// *************************************************** //\r
+\r
+RtApi :: RtApi()\r
+{\r
+  stream_.state = STREAM_CLOSED;\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.apiHandle = 0;\r
+  stream_.userBuffer[0] = 0;\r
+  stream_.userBuffer[1] = 0;\r
+  MUTEX_INITIALIZE( &stream_.mutex );\r
+  showWarnings_ = true;\r
+  firstErrorOccurred_ = false;\r
+}\r
+\r
+RtApi :: ~RtApi()\r
+{\r
+  MUTEX_DESTROY( &stream_.mutex );\r
+}\r
+\r
+void RtApi :: openStream( RtAudio::StreamParameters *oParams,\r
+                          RtAudio::StreamParameters *iParams,\r
+                          RtAudioFormat format, unsigned int sampleRate,\r
+                          unsigned int *bufferFrames,\r
+                          RtAudioCallback callback, void *userData,\r
+                          RtAudio::StreamOptions *options,\r
+                          RtAudioErrorCallback errorCallback )\r
+{\r
+  if ( stream_.state != STREAM_CLOSED ) {\r
+    errorText_ = "RtApi::openStream: a stream is already open!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+\r
+  // Clear stream information potentially left from a previously open stream.\r
+  clearStreamInfo();\r
+\r
+  if ( oParams && oParams->nChannels < 1 ) {\r
+    errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+\r
+  if ( iParams && iParams->nChannels < 1 ) {\r
+    errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+\r
+  if ( oParams == NULL && iParams == NULL ) {\r
+    errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+\r
+  if ( formatBytes(format) == 0 ) {\r
+    errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+\r
+  unsigned int nDevices = getDeviceCount();\r
+  unsigned int oChannels = 0;\r
+  if ( oParams ) {\r
+    oChannels = oParams->nChannels;\r
+    if ( oParams->deviceId >= nDevices ) {\r
+      errorText_ = "RtApi::openStream: output device parameter value is invalid.";\r
+      error( RtAudioError::INVALID_USE );\r
+      return;\r
+    }\r
+  }\r
+\r
+  unsigned int iChannels = 0;\r
+  if ( iParams ) {\r
+    iChannels = iParams->nChannels;\r
+    if ( iParams->deviceId >= nDevices ) {\r
+      errorText_ = "RtApi::openStream: input device parameter value is invalid.";\r
+      error( RtAudioError::INVALID_USE );\r
+      return;\r
+    }\r
+  }\r
+\r
+  bool result;\r
+\r
+  if ( oChannels > 0 ) {\r
+\r
+    result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,\r
+                              sampleRate, format, bufferFrames, options );\r
+    if ( result == false ) {\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  if ( iChannels > 0 ) {\r
+\r
+    result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,\r
+                              sampleRate, format, bufferFrames, options );\r
+    if ( result == false ) {\r
+      if ( oChannels > 0 ) closeStream();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  stream_.callbackInfo.callback = (void *) callback;\r
+  stream_.callbackInfo.userData = userData;\r
+  stream_.callbackInfo.errorCallback = (void *) errorCallback;\r
+\r
+  if ( options ) options->numberOfBuffers = stream_.nBuffers;\r
+  stream_.state = STREAM_STOPPED;\r
+}\r
+\r
+unsigned int RtApi :: getDefaultInputDevice( void )\r
+{\r
+  // Should be implemented in subclasses if possible.\r
+  return 0;\r
+}\r
+\r
+unsigned int RtApi :: getDefaultOutputDevice( void )\r
+{\r
+  // Should be implemented in subclasses if possible.\r
+  return 0;\r
+}\r
+\r
+void RtApi :: closeStream( void )\r
+{\r
+  // MUST be implemented in subclasses!\r
+  return;\r
+}\r
+\r
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,\r
+                               unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,\r
+                               RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,\r
+                               RtAudio::StreamOptions * /*options*/ )\r
+{\r
+  // MUST be implemented in subclasses!\r
+  return FAILURE;\r
+}\r
+\r
+void RtApi :: tickStreamTime( void )\r
+{\r
+  // Subclasses that do not provide their own implementation of\r
+  // getStreamTime should call this function once per buffer I/O to\r
+  // provide basic stream time support.\r
+\r
+  stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate );\r
+\r
+#if defined( HAVE_GETTIMEOFDAY )\r
+  gettimeofday( &stream_.lastTickTimestamp, NULL );\r
+#endif\r
+}\r
+\r
+long RtApi :: getStreamLatency( void )\r
+{\r
+  verifyStream();\r
+\r
+  long totalLatency = 0;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
+    totalLatency = stream_.latency[0];\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX )\r
+    totalLatency += stream_.latency[1];\r
+\r
+  return totalLatency;\r
+}\r
+\r
+double RtApi :: getStreamTime( void )\r
+{\r
+  verifyStream();\r
+\r
+#if defined( HAVE_GETTIMEOFDAY )\r
+  // Return a very accurate estimate of the stream time by\r
+  // adding in the elapsed time since the last tick.\r
+  struct timeval then;\r
+  struct timeval now;\r
+\r
+  if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 )\r
+    return stream_.streamTime;\r
+\r
+  gettimeofday( &now, NULL );\r
+  then = stream_.lastTickTimestamp;\r
+  return stream_.streamTime +\r
+    ((now.tv_sec + 0.000001 * now.tv_usec) -\r
+     (then.tv_sec + 0.000001 * then.tv_usec));     \r
+#else\r
+  return stream_.streamTime;\r
+#endif\r
+}\r
+\r
+void RtApi :: setStreamTime( double time )\r
+{\r
+  verifyStream();\r
+\r
+  if ( time >= 0.0 )\r
+    stream_.streamTime = time;\r
+}\r
+\r
+unsigned int RtApi :: getStreamSampleRate( void )\r
+{\r
+ verifyStream();\r
+\r
+ return stream_.sampleRate;\r
+}\r
+\r
+\r
+// *************************************************** //\r
+//\r
+// OS/API-specific methods.\r
+//\r
+// *************************************************** //\r
+\r
+#if defined(__MACOSX_CORE__)\r
+\r
+// The OS X CoreAudio API is designed to use a separate callback\r
+// procedure for each of its audio devices.  A single RtAudio duplex\r
+// stream using two different devices is supported here, though it\r
+// cannot be guaranteed to always behave correctly because we cannot\r
+// synchronize these two callbacks.\r
+//\r
+// A property listener is installed for over/underrun information.\r
+// However, no functionality is currently provided to allow property\r
+// listeners to trigger user handlers because it is unclear what could\r
+// be done if a critical stream parameter (buffer size, sample rate,\r
+// device disconnect) notification arrived.  The listeners entail\r
+// quite a bit of extra code and most likely, a user program wouldn't\r
+// be prepared for the result anyway.  However, we do provide a flag\r
+// to the client callback function to inform of an over/underrun.\r
+\r
+// A structure to hold various information related to the CoreAudio API\r
+// implementation.\r
+struct CoreHandle {\r
+  AudioDeviceID id[2];    // device ids\r
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
+  AudioDeviceIOProcID procId[2];\r
+#endif\r
+  UInt32 iStream[2];      // device stream index (or first if using multiple)\r
+  UInt32 nStreams[2];     // number of streams to use\r
+  bool xrun[2];\r
+  char *deviceBuffer;\r
+  pthread_cond_t condition;\r
+  int drainCounter;       // Tracks callback counts when draining\r
+  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
+\r
+  CoreHandle()\r
+    :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
+};\r
+\r
+RtApiCore:: RtApiCore()\r
+{\r
+#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
+  // This is a largely undocumented but absolutely necessary\r
+  // requirement starting with OS-X 10.6.  If not called, queries and\r
+  // updates to various audio device properties are not handled\r
+  // correctly.\r
+  CFRunLoopRef theRunLoop = NULL;\r
+  AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,\r
+                                          kAudioObjectPropertyScopeGlobal,\r
+                                          kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";\r
+    error( RtAudioError::WARNING );\r
+  }\r
+#endif\r
+}\r
+\r
+RtApiCore :: ~RtApiCore()\r
+{\r
+  // The subclass destructor gets called before the base class\r
+  // destructor, so close an existing stream before deallocating\r
+  // apiDeviceId memory.\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+}\r
+\r
+unsigned int RtApiCore :: getDeviceCount( void )\r
+{\r
+  // Find out how many audio devices there are, if any.\r
+  UInt32 dataSize;\r
+  AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  return dataSize / sizeof( AudioDeviceID );\r
+}\r
+\r
+unsigned int RtApiCore :: getDefaultInputDevice( void )\r
+{\r
+  unsigned int nDevices = getDeviceCount();\r
+  if ( nDevices <= 1 ) return 0;\r
+\r
+  AudioDeviceID id;\r
+  UInt32 dataSize = sizeof( AudioDeviceID );\r
+  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  dataSize *= nDevices;\r
+  AudioDeviceID deviceList[ nDevices ];\r
+  property.mSelector = kAudioHardwarePropertyDevices;\r
+  result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  for ( unsigned int i=0; i<nDevices; i++ )\r
+    if ( id == deviceList[i] ) return i;\r
+\r
+  errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";\r
+  error( RtAudioError::WARNING );\r
+  return 0;\r
+}\r
+\r
+unsigned int RtApiCore :: getDefaultOutputDevice( void )\r
+{\r
+  unsigned int nDevices = getDeviceCount();\r
+  if ( nDevices <= 1 ) return 0;\r
+\r
+  AudioDeviceID id;\r
+  UInt32 dataSize = sizeof( AudioDeviceID );\r
+  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  dataSize = sizeof( AudioDeviceID ) * nDevices;\r
+  AudioDeviceID deviceList[ nDevices ];\r
+  property.mSelector = kAudioHardwarePropertyDevices;\r
+  result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  for ( unsigned int i=0; i<nDevices; i++ )\r
+    if ( id == deviceList[i] ) return i;\r
+\r
+  errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";\r
+  error( RtAudioError::WARNING );\r
+  return 0;\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  // Get device ID\r
+  unsigned int nDevices = getDeviceCount();\r
+  if ( nDevices == 0 ) {\r
+    errorText_ = "RtApiCore::getDeviceInfo: no devices found!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  AudioDeviceID deviceList[ nDevices ];\r
+  UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;\r
+  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,\r
+                                          kAudioObjectPropertyScopeGlobal,\r
+                                          kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,\r
+                                                0, NULL, &dataSize, (void *) &deviceList );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  AudioDeviceID id = deviceList[ device ];\r
+\r
+  // Get the device name.\r
+  info.name.erase();\r
+  CFStringRef cfname;\r
+  dataSize = sizeof( CFStringRef );\r
+  property.mSelector = kAudioObjectPropertyManufacturer;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );\r
+  int length = CFStringGetLength(cfname);\r
+  char *mname = (char *)malloc(length * 3 + 1);\r
+#if defined( UNICODE ) || defined( _UNICODE )\r
+  CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8);\r
+#else\r
+  CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());\r
+#endif\r
+  info.name.append( (const char *)mname, strlen(mname) );\r
+  info.name.append( ": " );\r
+  CFRelease( cfname );\r
+  free(mname);\r
+\r
+  property.mSelector = kAudioObjectPropertyName;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );\r
+  length = CFStringGetLength(cfname);\r
+  char *name = (char *)malloc(length * 3 + 1);\r
+#if defined( UNICODE ) || defined( _UNICODE )\r
+  CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8);\r
+#else\r
+  CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());\r
+#endif\r
+  info.name.append( (const char *)name, strlen(name) );\r
+  CFRelease( cfname );\r
+  free(name);\r
+\r
+  // Get the output stream "configuration".\r
+  AudioBufferList      *bufferList = nil;\r
+  property.mSelector = kAudioDevicePropertyStreamConfiguration;\r
+  property.mScope = kAudioDevicePropertyScopeOutput;\r
+  //  property.mElement = kAudioObjectPropertyElementWildcard;\r
+  dataSize = 0;\r
+  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
+  if ( result != noErr || dataSize == 0 ) {\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Allocate the AudioBufferList.\r
+  bufferList = (AudioBufferList *) malloc( dataSize );\r
+  if ( bufferList == NULL ) {\r
+    errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
+  if ( result != noErr || dataSize == 0 ) {\r
+    free( bufferList );\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Get output channel information.\r
+  unsigned int i, nStreams = bufferList->mNumberBuffers;\r
+  for ( i=0; i<nStreams; i++ )\r
+    info.outputChannels += bufferList->mBuffers[i].mNumberChannels;\r
+  free( bufferList );\r
+\r
+  // Get the input stream "configuration".\r
+  property.mScope = kAudioDevicePropertyScopeInput;\r
+  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
+  if ( result != noErr || dataSize == 0 ) {\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Allocate the AudioBufferList.\r
+  bufferList = (AudioBufferList *) malloc( dataSize );\r
+  if ( bufferList == NULL ) {\r
+    errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
+  if (result != noErr || dataSize == 0) {\r
+    free( bufferList );\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Get input channel information.\r
+  nStreams = bufferList->mNumberBuffers;\r
+  for ( i=0; i<nStreams; i++ )\r
+    info.inputChannels += bufferList->mBuffers[i].mNumberChannels;\r
+  free( bufferList );\r
+\r
+  // If device opens for both playback and capture, we determine the channels.\r
+  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
+    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+\r
+  // Probe the device sample rates.\r
+  bool isInput = false;\r
+  if ( info.outputChannels == 0 ) isInput = true;\r
+\r
+  // Determine the supported sample rates.\r
+  property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;\r
+  if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput;\r
+  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
+  if ( result != kAudioHardwareNoError || dataSize == 0 ) {\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  UInt32 nRanges = dataSize / sizeof( AudioValueRange );\r
+  AudioValueRange rangeList[ nRanges ];\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList );\r
+  if ( result != kAudioHardwareNoError ) {\r
+    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // The sample rate reporting mechanism is a bit of a mystery.  It\r
+  // seems that it can either return individual rates or a range of\r
+  // rates.  I assume that if the min / max range values are the same,\r
+  // then that represents a single supported rate and if the min / max\r
+  // range values are different, the device supports an arbitrary\r
+  // range of values (though there might be multiple ranges, so we'll\r
+  // use the most conservative range).\r
+  Float64 minimumRate = 1.0, maximumRate = 10000000000.0;\r
+  bool haveValueRange = false;\r
+  info.sampleRates.clear();\r
+  for ( UInt32 i=0; i<nRanges; i++ ) {\r
+    if ( rangeList[i].mMinimum == rangeList[i].mMaximum )\r
+      info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );\r
+    else {\r
+      haveValueRange = true;\r
+      if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;\r
+      if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;\r
+    }\r
+  }\r
+\r
+  if ( haveValueRange ) {\r
+    for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
+      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )\r
+        info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+    }\r
+  }\r
+\r
+  // Sort and remove any redundant values\r
+  std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
+  info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );\r
+\r
+  if ( info.sampleRates.size() == 0 ) {\r
+    errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // CoreAudio always uses 32-bit floating point data for PCM streams.\r
+  // Thus, any other "physical" formats supported by the device are of\r
+  // no interest to the client.\r
+  info.nativeFormats = RTAUDIO_FLOAT32;\r
+\r
+  if ( info.outputChannels > 0 )\r
+    if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;\r
+  if ( info.inputChannels > 0 )\r
+    if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;\r
+\r
+  info.probed = true;\r
+  return info;\r
+}\r
+\r
+static OSStatus callbackHandler( AudioDeviceID inDevice,\r
+                                 const AudioTimeStamp* /*inNow*/,\r
+                                 const AudioBufferList* inInputData,\r
+                                 const AudioTimeStamp* /*inInputTime*/,\r
+                                 AudioBufferList* outOutputData,\r
+                                 const AudioTimeStamp* /*inOutputTime*/,\r
+                                 void* infoPointer )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
+\r
+  RtApiCore *object = (RtApiCore *) info->object;\r
+  if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )\r
+    return kAudioHardwareUnspecifiedError;\r
+  else\r
+    return kAudioHardwareNoError;\r
+}\r
+\r
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,\r
+                              UInt32 nAddresses,\r
+                              const AudioObjectPropertyAddress properties[],\r
+                              void* handlePointer )\r
+{\r
+  CoreHandle *handle = (CoreHandle *) handlePointer;\r
+  for ( UInt32 i=0; i<nAddresses; i++ ) {\r
+    if ( properties[i].mSelector == kAudioDeviceProcessorOverload ) {\r
+      if ( properties[i].mScope == kAudioDevicePropertyScopeInput )\r
+        handle->xrun[1] = true;\r
+      else\r
+        handle->xrun[0] = true;\r
+    }\r
+  }\r
+\r
+  return kAudioHardwareNoError;\r
+}\r
+\r
+static OSStatus rateListener( AudioObjectID inDevice,\r
+                              UInt32 /*nAddresses*/,\r
+                              const AudioObjectPropertyAddress /*properties*/[],\r
+                              void* ratePointer )\r
+{\r
+  Float64 *rate = (Float64 *) ratePointer;\r
+  UInt32 dataSize = sizeof( Float64 );\r
+  AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,\r
+                                          kAudioObjectPropertyScopeGlobal,\r
+                                          kAudioObjectPropertyElementMaster };\r
+  AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );\r
+  return kAudioHardwareNoError;\r
+}\r
+\r
+bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                   unsigned int firstChannel, unsigned int sampleRate,\r
+                                   RtAudioFormat format, unsigned int *bufferSize,\r
+                                   RtAudio::StreamOptions *options )\r
+{\r
+  // Get device ID\r
+  unsigned int nDevices = getDeviceCount();\r
+  if ( nDevices == 0 ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    errorText_ = "RtApiCore::probeDeviceOpen: no devices found!";\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!";\r
+    return FAILURE;\r
+  }\r
+\r
+  AudioDeviceID deviceList[ nDevices ];\r
+  UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;\r
+  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,\r
+                                          kAudioObjectPropertyScopeGlobal,\r
+                                          kAudioObjectPropertyElementMaster };\r
+  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,\r
+                                                0, NULL, &dataSize, (void *) &deviceList );\r
+  if ( result != noErr ) {\r
+    errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs.";\r
+    return FAILURE;\r
+  }\r
+\r
+  AudioDeviceID id = deviceList[ device ];\r
+\r
+  // Setup for stream mode.\r
+  bool isInput = false;\r
+  if ( mode == INPUT ) {\r
+    isInput = true;\r
+    property.mScope = kAudioDevicePropertyScopeInput;\r
+  }\r
+  else\r
+    property.mScope = kAudioDevicePropertyScopeOutput;\r
+\r
+  // Get the stream "configuration".\r
+  AudioBufferList      *bufferList = nil;\r
+  dataSize = 0;\r
+  property.mSelector = kAudioDevicePropertyStreamConfiguration;\r
+  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
+  if ( result != noErr || dataSize == 0 ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Allocate the AudioBufferList.\r
+  bufferList = (AudioBufferList *) malloc( dataSize );\r
+  if ( bufferList == NULL ) {\r
+    errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList.";\r
+    return FAILURE;\r
+  }\r
+\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
+  if (result != noErr || dataSize == 0) {\r
+    free( bufferList );\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Search for one or more streams that contain the desired number of\r
+  // channels. CoreAudio devices can have an arbitrary number of\r
+  // streams and each stream can have an arbitrary number of channels.\r
+  // For each stream, a single buffer of interleaved samples is\r
+  // provided.  RtAudio prefers the use of one stream of interleaved\r
+  // data or multiple consecutive single-channel streams.  However, we\r
+  // now support multiple consecutive multi-channel streams of\r
+  // interleaved data as well.\r
+  UInt32 iStream, offsetCounter = firstChannel;\r
+  UInt32 nStreams = bufferList->mNumberBuffers;\r
+  bool monoMode = false;\r
+  bool foundStream = false;\r
+\r
+  // First check that the device supports the requested number of\r
+  // channels.\r
+  UInt32 deviceChannels = 0;\r
+  for ( iStream=0; iStream<nStreams; iStream++ )\r
+    deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;\r
+\r
+  if ( deviceChannels < ( channels + firstChannel ) ) {\r
+    free( bufferList );\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Look for a single stream meeting our needs.\r
+  UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;\r
+  for ( iStream=0; iStream<nStreams; iStream++ ) {\r
+    streamChannels = bufferList->mBuffers[iStream].mNumberChannels;\r
+    if ( streamChannels >= channels + offsetCounter ) {\r
+      firstStream = iStream;\r
+      channelOffset = offsetCounter;\r
+      foundStream = true;\r
+      break;\r
+    }\r
+    if ( streamChannels > offsetCounter ) break;\r
+    offsetCounter -= streamChannels;\r
+  }\r
+\r
+  // If we didn't find a single stream above, then we should be able\r
+  // to meet the channel specification with multiple streams.\r
+  if ( foundStream == false ) {\r
+    monoMode = true;\r
+    offsetCounter = firstChannel;\r
+    for ( iStream=0; iStream<nStreams; iStream++ ) {\r
+      streamChannels = bufferList->mBuffers[iStream].mNumberChannels;\r
+      if ( streamChannels > offsetCounter ) break;\r
+      offsetCounter -= streamChannels;\r
+    }\r
+\r
+    firstStream = iStream;\r
+    channelOffset = offsetCounter;\r
+    Int32 channelCounter = channels + offsetCounter - streamChannels;\r
+\r
+    if ( streamChannels > 1 ) monoMode = false;\r
+    while ( channelCounter > 0 ) {\r
+      streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;\r
+      if ( streamChannels > 1 ) monoMode = false;\r
+      channelCounter -= streamChannels;\r
+      streamCount++;\r
+    }\r
+  }\r
+\r
+  free( bufferList );\r
+\r
+  // Determine the buffer size.\r
+  AudioValueRange      bufferRange;\r
+  dataSize = sizeof( AudioValueRange );\r
+  property.mSelector = kAudioDevicePropertyBufferFrameSizeRange;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange );\r
+\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum;\r
+  else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;\r
+  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;\r
+\r
+  // Set the buffer size.  For multiple streams, I'm assuming we only\r
+  // need to make this setting for the master channel.\r
+  UInt32 theSize = (UInt32) *bufferSize;\r
+  dataSize = sizeof( UInt32 );\r
+  property.mSelector = kAudioDevicePropertyBufferFrameSize;\r
+  result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize );\r
+\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // If attempting to setup a duplex stream, the bufferSize parameter\r
+  // MUST be the same in both directions!\r
+  *bufferSize = theSize;\r
+  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  stream_.bufferSize = *bufferSize;\r
+  stream_.nBuffers = 1;\r
+\r
+  // Try to set "hog" mode ... it's not clear to me this is working.\r
+  if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {\r
+    pid_t hog_pid;\r
+    dataSize = sizeof( hog_pid );\r
+    property.mSelector = kAudioDevicePropertyHogMode;\r
+    result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    if ( hog_pid != getpid() ) {\r
+      hog_pid = getpid();\r
+      result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid );\r
+      if ( result != noErr ) {\r
+        errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";\r
+        errorText_ = errorStream_.str();\r
+        return FAILURE;\r
+      }\r
+    }\r
+  }\r
+\r
+  // Check and if necessary, change the sample rate for the device.\r
+  Float64 nominalRate;\r
+  dataSize = sizeof( Float64 );\r
+  property.mSelector = kAudioDevicePropertyNominalSampleRate;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Only change the sample rate if off by more than 1 Hz.\r
+  if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {\r
+\r
+    // Set a property listener for the sample rate change\r
+    Float64 reportedRate = 0.0;\r
+    AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
+    result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    nominalRate = (Float64) sampleRate;\r
+    result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );\r
+    if ( result != noErr ) {\r
+      AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Now wait until the reported nominal rate is what we just set.\r
+    UInt32 microCounter = 0;\r
+    while ( reportedRate != nominalRate ) {\r
+      microCounter += 5000;\r
+      if ( microCounter > 5000000 ) break;\r
+      usleep( 5000 );\r
+    }\r
+\r
+    // Remove the property listener.\r
+    AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
+\r
+    if ( microCounter > 5000000 ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // Now set the stream format for all streams.  Also, check the\r
+  // physical format of the device and change that if necessary.\r
+  AudioStreamBasicDescription  description;\r
+  dataSize = sizeof( AudioStreamBasicDescription );\r
+  property.mSelector = kAudioStreamPropertyVirtualFormat;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the sample rate and data format id.  However, only make the\r
+  // change if the sample rate is not within 1.0 of the desired\r
+  // rate and the format is not linear pcm.\r
+  bool updateFormat = false;\r
+  if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {\r
+    description.mSampleRate = (Float64) sampleRate;\r
+    updateFormat = true;\r
+  }\r
+\r
+  if ( description.mFormatID != kAudioFormatLinearPCM ) {\r
+    description.mFormatID = kAudioFormatLinearPCM;\r
+    updateFormat = true;\r
+  }\r
+\r
+  if ( updateFormat ) {\r
+    result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // Now check the physical format.\r
+  property.mSelector = kAudioStreamPropertyPhysicalFormat;\r
+  result = AudioObjectGetPropertyData( id, &property, 0, NULL,  &dataSize, &description );\r
+  if ( result != noErr ) {\r
+    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  //std::cout << "Current physical stream format:" << std::endl;\r
+  //std::cout << "   mBitsPerChan = " << description.mBitsPerChannel << std::endl;\r
+  //std::cout << "   aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
+  //std::cout << "   bytesPerFrame = " << description.mBytesPerFrame << std::endl;\r
+  //std::cout << "   sample rate = " << description.mSampleRate << std::endl;\r
+\r
+  if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {\r
+    description.mFormatID = kAudioFormatLinearPCM;\r
+    //description.mSampleRate = (Float64) sampleRate;\r
+    AudioStreamBasicDescription        testDescription = description;\r
+    UInt32 formatFlags;\r
+\r
+    // We'll try higher bit rates first and then work our way down.\r
+    std::vector< std::pair<UInt32, UInt32>  > physicalFormats;\r
+    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger;\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
+    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) );   // 24-bit packed\r
+    formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low\r
+    formatFlags |= kAudioFormatFlagIsAlignedHigh;\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high\r
+    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );\r
+    physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );\r
+\r
+    bool setPhysicalFormat = false;\r
+    for( unsigned int i=0; i<physicalFormats.size(); i++ ) {\r
+      testDescription = description;\r
+      testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;\r
+      testDescription.mFormatFlags = physicalFormats[i].second;\r
+      if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )\r
+        testDescription.mBytesPerFrame =  4 * testDescription.mChannelsPerFrame;\r
+      else\r
+        testDescription.mBytesPerFrame =  testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
+      testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
+      result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );\r
+      if ( result == noErr ) {\r
+        setPhysicalFormat = true;\r
+        //std::cout << "Updated physical stream format:" << std::endl;\r
+        //std::cout << "   mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;\r
+        //std::cout << "   aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
+        //std::cout << "   bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;\r
+        //std::cout << "   sample rate = " << testDescription.mSampleRate << std::endl;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if ( !setPhysicalFormat ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  } // done setting virtual/physical formats.\r
+\r
+  // Get the stream / device latency.\r
+  UInt32 latency;\r
+  dataSize = sizeof( UInt32 );\r
+  property.mSelector = kAudioDevicePropertyLatency;\r
+  if ( AudioObjectHasProperty( id, &property ) == true ) {\r
+    result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &latency );\r
+    if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;\r
+    else {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::WARNING );\r
+    }\r
+  }\r
+\r
+  // Byte-swapping: According to AudioHardware.h, the stream data will\r
+  // always be presented in native-endian format, so we should never\r
+  // need to byte swap.\r
+  stream_.doByteSwap[mode] = false;\r
+\r
+  // From the CoreAudio documentation, PCM data must be supplied as\r
+  // 32-bit floats.\r
+  stream_.userFormat = format;\r
+  stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
+\r
+  if ( streamCount == 1 )\r
+    stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;\r
+  else // multiple streams\r
+    stream_.nDeviceChannels[mode] = channels;\r
+  stream_.nUserChannels[mode] = channels;\r
+  stream_.channelOffset[mode] = channelOffset;  // offset within a CoreAudio stream\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
+  stream_.deviceInterleaved[mode] = true;\r
+  if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;\r
+\r
+  // Set flags for buffer conversion.\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( streamCount == 1 ) {\r
+    if ( stream_.nUserChannels[mode] > 1 &&\r
+         stream_.userInterleaved != stream_.deviceInterleaved[mode] )\r
+      stream_.doConvertBuffer[mode] = true;\r
+  }\r
+  else if ( monoMode && stream_.userInterleaved )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate our CoreHandle structure for the stream.\r
+  CoreHandle *handle = 0;\r
+  if ( stream_.apiHandle == 0 ) {\r
+    try {\r
+      handle = new CoreHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory.";\r
+      goto error;\r
+    }\r
+\r
+    if ( pthread_cond_init( &handle->condition, NULL ) ) {\r
+      errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable.";\r
+      goto error;\r
+    }\r
+    stream_.apiHandle = (void *) handle;\r
+  }\r
+  else\r
+    handle = (CoreHandle *) stream_.apiHandle;\r
+  handle->iStream[mode] = firstStream;\r
+  handle->nStreams[mode] = streamCount;\r
+  handle->id[mode] = id;\r
+\r
+  // Allocate necessary internal buffers.\r
+  unsigned long bufferBytes;\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  //  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );\r
+  memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  // If possible, we will make use of the CoreAudio stream buffers as\r
+  // "device buffers".  However, we can't do this if using multiple\r
+  // streams.\r
+  if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.sampleRate = sampleRate;\r
+  stream_.device[mode] = device;\r
+  stream_.state = STREAM_STOPPED;\r
+  stream_.callbackInfo.object = (void *) this;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+    if ( streamCount > 1 ) setConvertInfo( mode, 0 );\r
+    else setConvertInfo( mode, channelOffset );\r
+  }\r
+\r
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )\r
+    // Only one callback procedure per device.\r
+    stream_.mode = DUPLEX;\r
+  else {\r
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
+    result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );\r
+#else\r
+    // deprecated in favor of AudioDeviceCreateIOProcID()\r
+    result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );\r
+#endif\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto error;\r
+    }\r
+    if ( stream_.mode == OUTPUT && mode == INPUT )\r
+      stream_.mode = DUPLEX;\r
+    else\r
+      stream_.mode = mode;\r
+  }\r
+\r
+  // Setup the device property listener for over/underload.\r
+  property.mSelector = kAudioDeviceProcessorOverload;\r
+  property.mScope = kAudioObjectPropertyScopeGlobal;\r
+  result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );\r
+\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( handle ) {\r
+    pthread_cond_destroy( &handle->condition );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.state = STREAM_CLOSED;\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiCore :: closeStream( void )\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiCore::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( stream_.state == STREAM_RUNNING )\r
+      AudioDeviceStop( handle->id[0], callbackHandler );\r
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
+    AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );\r
+#else\r
+    // deprecated in favor of AudioDeviceDestroyIOProcID()\r
+    AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );\r
+#endif\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
+    if ( stream_.state == STREAM_RUNNING )\r
+      AudioDeviceStop( handle->id[1], callbackHandler );\r
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
+    AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );\r
+#else\r
+    // deprecated in favor of AudioDeviceDestroyIOProcID()\r
+    AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );\r
+#endif\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  // Destroy pthread condition variable.\r
+  pthread_cond_destroy( &handle->condition );\r
+  delete handle;\r
+  stream_.apiHandle = 0;\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+void RtApiCore :: startStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiCore::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  OSStatus result = noErr;\r
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    result = AudioDeviceStart( handle->id[0], callbackHandler );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT ||\r
+       ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
+\r
+    result = AudioDeviceStart( handle->id[1], callbackHandler );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  handle->drainCounter = 0;\r
+  handle->internalDrain = false;\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+ unlock:\r
+  if ( result == noErr ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiCore :: stopStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  OSStatus result = noErr;\r
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    if ( handle->drainCounter == 0 ) {\r
+      handle->drainCounter = 2;\r
+      pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled\r
+    }\r
+\r
+    result = AudioDeviceStop( handle->id[0], callbackHandler );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
+\r
+    result = AudioDeviceStop( handle->id[1], callbackHandler );\r
+    if ( result != noErr ) {\r
+      errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+ unlock:\r
+  if ( result == noErr ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiCore :: abortStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
+  handle->drainCounter = 2;\r
+\r
+  stopStream();\r
+}\r
+\r
+// This function will be called by a spawned thread when the user\r
+// callback function signals that the stream should be stopped or\r
+// aborted.  It is better to handle it this way because the\r
+// callbackEvent() function probably should return before the AudioDeviceStop()\r
+// function is called.\r
+static void *coreStopStream( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiCore *object = (RtApiCore *) info->object;\r
+\r
+  object->stopStream();\r
+  pthread_exit( NULL );\r
+}\r
+\r
+bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,\r
+                                 const AudioBufferList *inBufferList,\r
+                                 const AudioBufferList *outBufferList )\r
+{\r
+  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return FAILURE;\r
+  }\r
+\r
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
+\r
+  // Check if we were draining the stream and signal is finished.\r
+  if ( handle->drainCounter > 3 ) {\r
+    ThreadHandle threadId;\r
+\r
+    stream_.state = STREAM_STOPPING;\r
+    if ( handle->internalDrain == true )\r
+      pthread_create( &threadId, NULL, coreStopStream, info );\r
+    else // external call to stopStream()\r
+      pthread_cond_signal( &handle->condition );\r
+    return SUCCESS;\r
+  }\r
+\r
+  AudioDeviceID outputDevice = handle->id[0];\r
+\r
+  // Invoke user callback to get fresh output data UNLESS we are\r
+  // draining stream or duplex mode AND the input/output devices are\r
+  // different AND this function is called for the input device.\r
+  if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) {\r
+    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
+    double streamTime = getStreamTime();\r
+    RtAudioStreamStatus status = 0;\r
+    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
+      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+      handle->xrun[0] = false;\r
+    }\r
+    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
+      status |= RTAUDIO_INPUT_OVERFLOW;\r
+      handle->xrun[1] = false;\r
+    }\r
+\r
+    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                                  stream_.bufferSize, streamTime, status, info->userData );\r
+    if ( cbReturnValue == 2 ) {\r
+      stream_.state = STREAM_STOPPING;\r
+      handle->drainCounter = 2;\r
+      abortStream();\r
+      return SUCCESS;\r
+    }\r
+    else if ( cbReturnValue == 1 ) {\r
+      handle->drainCounter = 1;\r
+      handle->internalDrain = true;\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {\r
+\r
+    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
+\r
+      if ( handle->nStreams[0] == 1 ) {\r
+        memset( outBufferList->mBuffers[handle->iStream[0]].mData,\r
+                0,\r
+                outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );\r
+      }\r
+      else { // fill multiple streams with zeros\r
+        for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {\r
+          memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,\r
+                  0,\r
+                  outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );\r
+        }\r
+      }\r
+    }\r
+    else if ( handle->nStreams[0] == 1 ) {\r
+      if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer\r
+        convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,\r
+                       stream_.userBuffer[0], stream_.convertInfo[0] );\r
+      }\r
+      else { // copy from user buffer\r
+        memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,\r
+                stream_.userBuffer[0],\r
+                outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );\r
+      }\r
+    }\r
+    else { // fill multiple streams\r
+      Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];\r
+      if ( stream_.doConvertBuffer[0] ) {\r
+        convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+        inBuffer = (Float32 *) stream_.deviceBuffer;\r
+      }\r
+\r
+      if ( stream_.deviceInterleaved[0] == false ) { // mono mode\r
+        UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;\r
+        for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
+          memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,\r
+                  (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );\r
+        }\r
+      }\r
+      else { // fill multiple multi-channel streams with interleaved data\r
+        UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;\r
+        Float32 *out, *in;\r
+\r
+        bool inInterleaved = ( stream_.userInterleaved ) ? true : false;\r
+        UInt32 inChannels = stream_.nUserChannels[0];\r
+        if ( stream_.doConvertBuffer[0] ) {\r
+          inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode\r
+          inChannels = stream_.nDeviceChannels[0];\r
+        }\r
+\r
+        if ( inInterleaved ) inOffset = 1;\r
+        else inOffset = stream_.bufferSize;\r
+\r
+        channelsLeft = inChannels;\r
+        for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {\r
+          in = inBuffer;\r
+          out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;\r
+          streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;\r
+\r
+          outJump = 0;\r
+          // Account for possible channel offset in first stream\r
+          if ( i == 0 && stream_.channelOffset[0] > 0 ) {\r
+            streamChannels -= stream_.channelOffset[0];\r
+            outJump = stream_.channelOffset[0];\r
+            out += outJump;\r
+          }\r
+\r
+          // Account for possible unfilled channels at end of the last stream\r
+          if ( streamChannels > channelsLeft ) {\r
+            outJump = streamChannels - channelsLeft;\r
+            streamChannels = channelsLeft;\r
+          }\r
+\r
+          // Determine input buffer offsets and skips\r
+          if ( inInterleaved ) {\r
+            inJump = inChannels;\r
+            in += inChannels - channelsLeft;\r
+          }\r
+          else {\r
+            inJump = 1;\r
+            in += (inChannels - channelsLeft) * inOffset;\r
+          }\r
+\r
+          for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {\r
+            for ( unsigned int j=0; j<streamChannels; j++ ) {\r
+              *out++ = in[j*inOffset];\r
+            }\r
+            out += outJump;\r
+            in += inJump;\r
+          }\r
+          channelsLeft -= streamChannels;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  // Don't bother draining input\r
+  if ( handle->drainCounter ) {\r
+    handle->drainCounter++;\r
+    goto unlock;\r
+  }\r
+\r
+  AudioDeviceID inputDevice;\r
+  inputDevice = handle->id[1];\r
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {\r
+\r
+    if ( handle->nStreams[1] == 1 ) {\r
+      if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer\r
+        convertBuffer( stream_.userBuffer[1],\r
+                       (char *) inBufferList->mBuffers[handle->iStream[1]].mData,\r
+                       stream_.convertInfo[1] );\r
+      }\r
+      else { // copy to user buffer\r
+        memcpy( stream_.userBuffer[1],\r
+                inBufferList->mBuffers[handle->iStream[1]].mData,\r
+                inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );\r
+      }\r
+    }\r
+    else { // read from multiple streams\r
+      Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];\r
+      if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;\r
+\r
+      if ( stream_.deviceInterleaved[1] == false ) { // mono mode\r
+        UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;\r
+        for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
+          memcpy( (void *)&outBuffer[i*stream_.bufferSize],\r
+                  inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );\r
+        }\r
+      }\r
+      else { // read from multiple multi-channel streams\r
+        UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;\r
+        Float32 *out, *in;\r
+\r
+        bool outInterleaved = ( stream_.userInterleaved ) ? true : false;\r
+        UInt32 outChannels = stream_.nUserChannels[1];\r
+        if ( stream_.doConvertBuffer[1] ) {\r
+          outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode\r
+          outChannels = stream_.nDeviceChannels[1];\r
+        }\r
+\r
+        if ( outInterleaved ) outOffset = 1;\r
+        else outOffset = stream_.bufferSize;\r
+\r
+        channelsLeft = outChannels;\r
+        for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {\r
+          out = outBuffer;\r
+          in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;\r
+          streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;\r
+\r
+          inJump = 0;\r
+          // Account for possible channel offset in first stream\r
+          if ( i == 0 && stream_.channelOffset[1] > 0 ) {\r
+            streamChannels -= stream_.channelOffset[1];\r
+            inJump = stream_.channelOffset[1];\r
+            in += inJump;\r
+          }\r
+\r
+          // Account for possible unread channels at end of the last stream\r
+          if ( streamChannels > channelsLeft ) {\r
+            inJump = streamChannels - channelsLeft;\r
+            streamChannels = channelsLeft;\r
+          }\r
+\r
+          // Determine output buffer offsets and skips\r
+          if ( outInterleaved ) {\r
+            outJump = outChannels;\r
+            out += outChannels - channelsLeft;\r
+          }\r
+          else {\r
+            outJump = 1;\r
+            out += (outChannels - channelsLeft) * outOffset;\r
+          }\r
+\r
+          for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {\r
+            for ( unsigned int j=0; j<streamChannels; j++ ) {\r
+              out[j*outOffset] = *in++;\r
+            }\r
+            out += outJump;\r
+            in += inJump;\r
+          }\r
+          channelsLeft -= streamChannels;\r
+        }\r
+      }\r
+      \r
+      if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer\r
+        convertBuffer( stream_.userBuffer[1],\r
+                       stream_.deviceBuffer,\r
+                       stream_.convertInfo[1] );\r
+      }\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  //MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  RtApi::tickStreamTime();\r
+  return SUCCESS;\r
+}\r
+\r
+const char* RtApiCore :: getErrorCode( OSStatus code )\r
+{\r
+  switch( code ) {\r
+\r
+  case kAudioHardwareNotRunningError:\r
+    return "kAudioHardwareNotRunningError";\r
+\r
+  case kAudioHardwareUnspecifiedError:\r
+    return "kAudioHardwareUnspecifiedError";\r
+\r
+  case kAudioHardwareUnknownPropertyError:\r
+    return "kAudioHardwareUnknownPropertyError";\r
+\r
+  case kAudioHardwareBadPropertySizeError:\r
+    return "kAudioHardwareBadPropertySizeError";\r
+\r
+  case kAudioHardwareIllegalOperationError:\r
+    return "kAudioHardwareIllegalOperationError";\r
+\r
+  case kAudioHardwareBadObjectError:\r
+    return "kAudioHardwareBadObjectError";\r
+\r
+  case kAudioHardwareBadDeviceError:\r
+    return "kAudioHardwareBadDeviceError";\r
+\r
+  case kAudioHardwareBadStreamError:\r
+    return "kAudioHardwareBadStreamError";\r
+\r
+  case kAudioHardwareUnsupportedOperationError:\r
+    return "kAudioHardwareUnsupportedOperationError";\r
+\r
+  case kAudioDeviceUnsupportedFormatError:\r
+    return "kAudioDeviceUnsupportedFormatError";\r
+\r
+  case kAudioDevicePermissionsError:\r
+    return "kAudioDevicePermissionsError";\r
+\r
+  default:\r
+    return "CoreAudio unknown error";\r
+  }\r
+}\r
+\r
+  //******************** End of __MACOSX_CORE__ *********************//\r
+#endif\r
+\r
+#if defined(__UNIX_JACK__)\r
+\r
+// JACK is a low-latency audio server, originally written for the\r
+// GNU/Linux operating system and now also ported to OS-X. It can\r
+// connect a number of different applications to an audio device, as\r
+// well as allowing them to share audio between themselves.\r
+//\r
+// When using JACK with RtAudio, "devices" refer to JACK clients that\r
+// have ports connected to the server.  The JACK server is typically\r
+// started in a terminal as follows:\r
+//\r
+// .jackd -d alsa -d hw:0\r
+//\r
+// or through an interface program such as qjackctl.  Many of the\r
+// parameters normally set for a stream are fixed by the JACK server\r
+// and can be specified when the JACK server is started.  In\r
+// particular,\r
+//\r
+// .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4\r
+//\r
+// specifies a sample rate of 44100 Hz, a buffer size of 512 sample\r
+// frames, and number of buffers = 4.  Once the server is running, it\r
+// is not possible to override these values.  If the values are not\r
+// specified in the command-line, the JACK server uses default values.\r
+//\r
+// The JACK server does not have to be running when an instance of\r
+// RtApiJack is created, though the function getDeviceCount() will\r
+// report 0 devices found until JACK has been started.  When no\r
+// devices are available (i.e., the JACK server is not running), a\r
+// stream cannot be opened.\r
+\r
+#include <jack/jack.h>\r
+#include <unistd.h>\r
+#include <cstdio>\r
+\r
+// A structure to hold various information related to the Jack API\r
+// implementation.\r
+struct JackHandle {\r
+  jack_client_t *client;\r
+  jack_port_t **ports[2];\r
+  std::string deviceName[2];\r
+  bool xrun[2];\r
+  pthread_cond_t condition;\r
+  int drainCounter;       // Tracks callback counts when draining\r
+  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
+\r
+  JackHandle()\r
+    :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }\r
+};\r
+\r
+/* --- Monocasual hack ---------------------------------------------- */\r
+#ifdef __linux__\r
+void *RtApi :: __HACK__getJackClient() {\r
+       JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+       return (void*) handle->client;\r
+}\r
+#endif\r
+/* ------------------------------------------------------------------ */\r
+\r
+static void jackSilentError( const char * ) {};\r
+\r
+RtApiJack :: RtApiJack()\r
+{\r
+  // Nothing to do here.\r
+#if !defined(__RTAUDIO_DEBUG__)\r
+  // Turn off Jack's internal error reporting.\r
+  jack_set_error_function( &jackSilentError );\r
+#endif\r
+}\r
+\r
+RtApiJack :: ~RtApiJack()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+}\r
+\r
+unsigned int RtApiJack :: getDeviceCount( void )\r
+{\r
+  // See if we can become a jack client.\r
+  jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;\r
+  jack_status_t *status = NULL;\r
+  jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );\r
+  if ( client == 0 ) return 0;\r
+\r
+  const char **ports;\r
+  std::string port, previousPort;\r
+  unsigned int nChannels = 0, nDevices = 0;\r
+  ports = jack_get_ports( client, NULL, NULL, 0 );\r
+  if ( ports ) {\r
+    // Parse the port names up to the first colon (:).\r
+    size_t iColon = 0;\r
+    do {\r
+      port = (char *) ports[ nChannels ];\r
+      iColon = port.find(":");\r
+      if ( iColon != std::string::npos ) {\r
+        port = port.substr( 0, iColon + 1 );\r
+        if ( port != previousPort ) {\r
+          nDevices++;\r
+          previousPort = port;\r
+        }\r
+      }\r
+    } while ( ports[++nChannels] );\r
+    free( ports );\r
+  }\r
+\r
+  jack_client_close( client );\r
+  return nDevices;\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption\r
+  jack_status_t *status = NULL;\r
+  jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );\r
+  if ( client == 0 ) {\r
+    errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  const char **ports;\r
+  std::string port, previousPort;\r
+  unsigned int nPorts = 0, nDevices = 0;\r
+  ports = jack_get_ports( client, NULL, NULL, 0 );\r
+  if ( ports ) {\r
+    // Parse the port names up to the first colon (:).\r
+    size_t iColon = 0;\r
+    do {\r
+      port = (char *) ports[ nPorts ];\r
+      iColon = port.find(":");\r
+      if ( iColon != std::string::npos ) {\r
+        port = port.substr( 0, iColon );\r
+        if ( port != previousPort ) {\r
+          if ( nDevices == device ) info.name = port;\r
+          nDevices++;\r
+          previousPort = port;\r
+        }\r
+      }\r
+    } while ( ports[++nPorts] );\r
+    free( ports );\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    jack_client_close( client );\r
+    errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  // Get the current jack server sample rate.\r
+  info.sampleRates.clear();\r
+  info.sampleRates.push_back( jack_get_sample_rate( client ) );\r
+\r
+  // Count the available ports containing the client name as device\r
+  // channels.  Jack "input ports" equal RtAudio output channels.\r
+  unsigned int nChannels = 0;\r
+  ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );\r
+  if ( ports ) {\r
+    while ( ports[ nChannels ] ) nChannels++;\r
+    free( ports );\r
+    info.outputChannels = nChannels;\r
+  }\r
+\r
+  // Jack "output ports" equal RtAudio input channels.\r
+  nChannels = 0;\r
+  ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );\r
+  if ( ports ) {\r
+    while ( ports[ nChannels ] ) nChannels++;\r
+    free( ports );\r
+    info.inputChannels = nChannels;\r
+  }\r
+\r
+  if ( info.outputChannels == 0 && info.inputChannels == 0 ) {\r
+    jack_client_close(client);\r
+    errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // If device opens for both playback and capture, we determine the channels.\r
+  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
+    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+\r
+  // Jack always uses 32-bit floats.\r
+  info.nativeFormats = RTAUDIO_FLOAT32;\r
+\r
+  // Jack doesn't provide default devices so we'll use the first available one.\r
+  if ( device == 0 && info.outputChannels > 0 )\r
+    info.isDefaultOutput = true;\r
+  if ( device == 0 && info.inputChannels > 0 )\r
+    info.isDefaultInput = true;\r
+\r
+  jack_client_close(client);\r
+  info.probed = true;\r
+  return info;\r
+}\r
+\r
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
+\r
+  RtApiJack *object = (RtApiJack *) info->object;\r
+  if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1;\r
+\r
+  return 0;\r
+}\r
+\r
+// This function will be called by a spawned thread when the Jack\r
+// server signals that it is shutting down.  It is necessary to handle\r
+// it this way because the jackShutdown() function must return before\r
+// the jack_deactivate() function (in closeStream()) will return.\r
+static void *jackCloseStream( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiJack *object = (RtApiJack *) info->object;\r
+\r
+  object->closeStream();\r
+\r
+  pthread_exit( NULL );\r
+}\r
+static void jackShutdown( void *infoPointer )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
+  RtApiJack *object = (RtApiJack *) info->object;\r
+\r
+  // Check current stream state.  If stopped, then we'll assume this\r
+  // was called as a result of a call to RtApiJack::stopStream (the\r
+  // deactivation of a client handle causes this function to be called).\r
+  // If not, we'll assume the Jack server is shutting down or some\r
+  // other problem occurred and we should close the stream.\r
+  if ( object->isStreamRunning() == false ) return;\r
+\r
+  ThreadHandle threadId;\r
+  pthread_create( &threadId, NULL, jackCloseStream, info );\r
+  std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;\r
+}\r
+\r
+static int jackXrun( void *infoPointer )\r
+{\r
+  JackHandle *handle = (JackHandle *) infoPointer;\r
+\r
+  if ( handle->ports[0] ) handle->xrun[0] = true;\r
+  if ( handle->ports[1] ) handle->xrun[1] = true;\r
+\r
+  return 0;\r
+}\r
+\r
+bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                   unsigned int firstChannel, unsigned int sampleRate,\r
+                                   RtAudioFormat format, unsigned int *bufferSize,\r
+                                   RtAudio::StreamOptions *options )\r
+{\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+\r
+  // Look for jack server and try to become a client (only do once per stream).\r
+  jack_client_t *client = 0;\r
+  if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {\r
+    jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;\r
+    jack_status_t *status = NULL;\r
+    if ( options && !options->streamName.empty() )\r
+      client = jack_client_open( options->streamName.c_str(), jackoptions, status );\r
+    else\r
+      client = jack_client_open( "RtApiJack", jackoptions, status );\r
+    if ( client == 0 ) {\r
+      errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";\r
+      error( RtAudioError::WARNING );\r
+      return FAILURE;\r
+    }\r
+  }\r
+  else {\r
+    // The handle must have been created on an earlier pass.\r
+    client = handle->client;\r
+  }\r
+\r
+  const char **ports;\r
+  std::string port, previousPort, deviceName;\r
+  unsigned int nPorts = 0, nDevices = 0;\r
+  ports = jack_get_ports( client, NULL, NULL, 0 );\r
+  if ( ports ) {\r
+    // Parse the port names up to the first colon (:).\r
+    size_t iColon = 0;\r
+    do {\r
+      port = (char *) ports[ nPorts ];\r
+      iColon = port.find(":");\r
+      if ( iColon != std::string::npos ) {\r
+        port = port.substr( 0, iColon );\r
+        if ( port != previousPort ) {\r
+          if ( nDevices == device ) deviceName = port;\r
+          nDevices++;\r
+          previousPort = port;\r
+        }\r
+      }\r
+    } while ( ports[++nPorts] );\r
+    free( ports );\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";\r
+    return FAILURE;\r
+  }\r
+\r
+  // Count the available ports containing the client name as device\r
+  // channels.  Jack "input ports" equal RtAudio output channels.\r
+  unsigned int nChannels = 0;\r
+  unsigned long flag = JackPortIsInput;\r
+  if ( mode == INPUT ) flag = JackPortIsOutput;\r
+  ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );\r
+  if ( ports ) {\r
+    while ( ports[ nChannels ] ) nChannels++;\r
+    free( ports );\r
+  }\r
+\r
+  // Compare the jack ports for specified client to the requested number of channels.\r
+  if ( nChannels < (channels + firstChannel) ) {\r
+    errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Check the jack server sample rate.\r
+  unsigned int jackRate = jack_get_sample_rate( client );\r
+  if ( sampleRate != jackRate ) {\r
+    jack_client_close( client );\r
+    errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  stream_.sampleRate = jackRate;\r
+\r
+  // Get the latency of the JACK port.\r
+  ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );\r
+  if ( ports[ firstChannel ] ) {\r
+    // Added by Ge Wang\r
+    jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);\r
+    // the range (usually the min and max are equal)\r
+    jack_latency_range_t latrange; latrange.min = latrange.max = 0;\r
+    // get the latency range\r
+    jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );\r
+    // be optimistic, use the min!\r
+    stream_.latency[mode] = latrange.min;\r
+    //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );\r
+  }\r
+  free( ports );\r
+\r
+  // The jack server always uses 32-bit floating-point data.\r
+  stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
+  stream_.userFormat = format;\r
+\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
+\r
+  // Jack always uses non-interleaved buffers.\r
+  stream_.deviceInterleaved[mode] = false;\r
+\r
+  // Jack always provides host byte-ordered data.\r
+  stream_.doByteSwap[mode] = false;\r
+\r
+  // Get the buffer size.  The buffer size and number of buffers\r
+  // (periods) is set when the jack server is started.\r
+  stream_.bufferSize = (int) jack_get_buffer_size( client );\r
+  *bufferSize = stream_.bufferSize;\r
+\r
+  stream_.nDeviceChannels[mode] = channels;\r
+  stream_.nUserChannels[mode] = channels;\r
+\r
+  // Set flags for buffer conversion.\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+       stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate our JackHandle structure for the stream.\r
+  if ( handle == 0 ) {\r
+    try {\r
+      handle = new JackHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory.";\r
+      goto error;\r
+    }\r
+\r
+    if ( pthread_cond_init(&handle->condition, NULL) ) {\r
+      errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable.";\r
+      goto error;\r
+    }\r
+    stream_.apiHandle = (void *) handle;\r
+    handle->client = client;\r
+  }\r
+  handle->deviceName[mode] = deviceName;\r
+\r
+  // Allocate necessary internal buffers.\r
+  unsigned long bufferBytes;\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    if ( mode == OUTPUT )\r
+      bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+    else { // mode == INPUT\r
+      bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] );\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);\r
+        if ( bufferBytes < bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  // Allocate memory for the Jack ports (channels) identifiers.\r
+  handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );\r
+  if ( handle->ports[mode] == NULL )  {\r
+    errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory.";\r
+    goto error;\r
+  }\r
+\r
+  stream_.device[mode] = device;\r
+  stream_.channelOffset[mode] = firstChannel;\r
+  stream_.state = STREAM_STOPPED;\r
+  stream_.callbackInfo.object = (void *) this;\r
+\r
+  if ( stream_.mode == OUTPUT && mode == INPUT )\r
+    // We had already set up the stream for output.\r
+    stream_.mode = DUPLEX;\r
+  else {\r
+    stream_.mode = mode;\r
+    jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );\r
+    jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );\r
+    jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );\r
+  }\r
+\r
+  // Register our ports.\r
+  char label[64];\r
+  if ( mode == OUTPUT ) {\r
+    for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
+      snprintf( label, 64, "outport %d", i );\r
+      handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,\r
+                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );\r
+    }\r
+  }\r
+  else {\r
+    for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
+      snprintf( label, 64, "inport %d", i );\r
+      handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,\r
+                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );\r
+    }\r
+  }\r
+\r
+  // Setup the buffer conversion information structure.  We don't use\r
+  // buffers to do channel offsets, so we override that parameter\r
+  // here.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );\r
+\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( handle ) {\r
+    pthread_cond_destroy( &handle->condition );\r
+    jack_client_close( handle->client );\r
+\r
+    if ( handle->ports[0] ) free( handle->ports[0] );\r
+    if ( handle->ports[1] ) free( handle->ports[1] );\r
+\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiJack :: closeStream( void )\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiJack::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+  if ( handle ) {\r
+\r
+    if ( stream_.state == STREAM_RUNNING )\r
+      jack_deactivate( handle->client );\r
+\r
+    jack_client_close( handle->client );\r
+  }\r
+\r
+  if ( handle ) {\r
+    if ( handle->ports[0] ) free( handle->ports[0] );\r
+    if ( handle->ports[1] ) free( handle->ports[1] );\r
+    pthread_cond_destroy( &handle->condition );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+void RtApiJack :: startStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiJack::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+  int result = jack_activate( handle->client );\r
+  if ( result ) {\r
+    errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";\r
+    goto unlock;\r
+  }\r
+\r
+  const char **ports;\r
+\r
+  // Get the list of available ports.\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    result = 1;\r
+    ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);\r
+    if ( ports == NULL) {\r
+      errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";\r
+      goto unlock;\r
+    }\r
+\r
+    // Now make the port connections.  Since RtAudio wasn't designed to\r
+    // allow the user to select particular channels of a device, we'll\r
+    // just open the first "nChannels" ports with offset.\r
+    for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
+      result = 1;\r
+      if ( ports[ stream_.channelOffset[0] + i ] )\r
+        result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );\r
+      if ( result ) {\r
+        free( ports );\r
+        errorText_ = "RtApiJack::startStream(): error connecting output ports!";\r
+        goto unlock;\r
+      }\r
+    }\r
+    free(ports);\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+    result = 1;\r
+    ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );\r
+    if ( ports == NULL) {\r
+      errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";\r
+      goto unlock;\r
+    }\r
+\r
+    // Now make the port connections.  See note above.\r
+    for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
+      result = 1;\r
+      if ( ports[ stream_.channelOffset[1] + i ] )\r
+        result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );\r
+      if ( result ) {\r
+        free( ports );\r
+        errorText_ = "RtApiJack::startStream(): error connecting input ports!";\r
+        goto unlock;\r
+      }\r
+    }\r
+    free(ports);\r
+  }\r
+\r
+  handle->drainCounter = 0;\r
+  handle->internalDrain = false;\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+ unlock:\r
+  if ( result == 0 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiJack :: stopStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    if ( handle->drainCounter == 0 ) {\r
+      handle->drainCounter = 2;\r
+      pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled\r
+    }\r
+  }\r
+\r
+  jack_deactivate( handle->client );\r
+  stream_.state = STREAM_STOPPED;\r
+}\r
+\r
+void RtApiJack :: abortStream( void )\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+  handle->drainCounter = 2;\r
+\r
+  stopStream();\r
+}\r
+\r
+// This function will be called by a spawned thread when the user\r
+// callback function signals that the stream should be stopped or\r
+// aborted.  It is necessary to handle it this way because the\r
+// callbackEvent() function must return before the jack_deactivate()\r
+// function will return.\r
+static void *jackStopStream( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiJack *object = (RtApiJack *) info->object;\r
+\r
+  object->stopStream();\r
+  pthread_exit( NULL );\r
+}\r
+\r
+bool RtApiJack :: callbackEvent( unsigned long nframes )\r
+{\r
+  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return FAILURE;\r
+  }\r
+  if ( stream_.bufferSize != nframes ) {\r
+    errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";\r
+    error( RtAudioError::WARNING );\r
+    return FAILURE;\r
+  }\r
+\r
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
+\r
+  // Check if we were draining the stream and signal is finished.\r
+  if ( handle->drainCounter > 3 ) {\r
+    ThreadHandle threadId;\r
+\r
+    stream_.state = STREAM_STOPPING;\r
+    if ( handle->internalDrain == true )\r
+      pthread_create( &threadId, NULL, jackStopStream, info );\r
+    else\r
+      pthread_cond_signal( &handle->condition );\r
+    return SUCCESS;\r
+  }\r
+\r
+  // Invoke user callback first, to get fresh output data.\r
+  if ( handle->drainCounter == 0 ) {\r
+    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
+    double streamTime = getStreamTime();\r
+    RtAudioStreamStatus status = 0;\r
+    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
+      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+      handle->xrun[0] = false;\r
+    }\r
+    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
+      status |= RTAUDIO_INPUT_OVERFLOW;\r
+      handle->xrun[1] = false;\r
+    }\r
+    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                                  stream_.bufferSize, streamTime, status, info->userData );\r
+    if ( cbReturnValue == 2 ) {\r
+      stream_.state = STREAM_STOPPING;\r
+      handle->drainCounter = 2;\r
+      ThreadHandle id;\r
+      pthread_create( &id, NULL, jackStopStream, info );\r
+      return SUCCESS;\r
+    }\r
+    else if ( cbReturnValue == 1 ) {\r
+      handle->drainCounter = 1;\r
+      handle->internalDrain = true;\r
+    }\r
+  }\r
+\r
+  jack_default_audio_sample_t *jackbuffer;\r
+  unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t );\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
+\r
+      for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {\r
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
+        memset( jackbuffer, 0, bufferBytes );\r
+      }\r
+\r
+    }\r
+    else if ( stream_.doConvertBuffer[0] ) {\r
+\r
+      convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+\r
+      for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {\r
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
+        memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );\r
+      }\r
+    }\r
+    else { // no buffer conversion\r
+      for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
+        memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );\r
+      }\r
+    }\r
+  }\r
+\r
+  // Don't bother draining input\r
+  if ( handle->drainCounter ) {\r
+    handle->drainCounter++;\r
+    goto unlock;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    if ( stream_.doConvertBuffer[1] ) {\r
+      for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {\r
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );\r
+        memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );\r
+      }\r
+      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
+    }\r
+    else { // no buffer conversion\r
+      for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );\r
+        memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );\r
+      }\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  RtApi::tickStreamTime();\r
+  return SUCCESS;\r
+}\r
+  //******************** End of __UNIX_JACK__ *********************//\r
+#endif\r
+\r
+#if defined(__WINDOWS_ASIO__) // ASIO API on Windows\r
+\r
+// The ASIO API is designed around a callback scheme, so this\r
+// implementation is similar to that used for OS-X CoreAudio and Linux\r
+// Jack.  The primary constraint with ASIO is that it only allows\r
+// access to a single driver at a time.  Thus, it is not possible to\r
+// have more than one simultaneous RtAudio stream.\r
+//\r
+// This implementation also requires a number of external ASIO files\r
+// and a few global variables.  The ASIO callback scheme does not\r
+// allow for the passing of user data, so we must create a global\r
+// pointer to our callbackInfo structure.\r
+//\r
+// On unix systems, we make use of a pthread condition variable.\r
+// Since there is no equivalent in Windows, I hacked something based\r
+// on information found in\r
+// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.\r
+\r
+#include "asiosys.h"\r
+#include "asio.h"\r
+#include "iasiothiscallresolver.h"\r
+#include "asiodrivers.h"\r
+#include <cmath>\r
+\r
+static AsioDrivers drivers;\r
+static ASIOCallbacks asioCallbacks;\r
+static ASIODriverInfo driverInfo;\r
+static CallbackInfo *asioCallbackInfo;\r
+static bool asioXRun;\r
+\r
+struct AsioHandle {\r
+  int drainCounter;       // Tracks callback counts when draining\r
+  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
+  ASIOBufferInfo *bufferInfos;\r
+  HANDLE condition;\r
+\r
+  AsioHandle()\r
+    :drainCounter(0), internalDrain(false), bufferInfos(0) {}\r
+};\r
+\r
+// Function declarations (definitions at end of section)\r
+static const char* getAsioErrorString( ASIOError result );\r
+static void sampleRateChanged( ASIOSampleRate sRate );\r
+static long asioMessages( long selector, long value, void* message, double* opt );\r
+\r
+RtApiAsio :: RtApiAsio()\r
+{\r
+  // ASIO cannot run on a multi-threaded appartment. You can call\r
+  // CoInitialize beforehand, but it must be for appartment threading\r
+  // (in which case, CoInitilialize will return S_FALSE here).\r
+  coInitialized_ = false;\r
+  HRESULT hr = CoInitialize( NULL ); \r
+  if ( FAILED(hr) ) {\r
+    errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";\r
+    error( RtAudioError::WARNING );\r
+  }\r
+  coInitialized_ = true;\r
+\r
+  drivers.removeCurrentDriver();\r
+  driverInfo.asioVersion = 2;\r
+\r
+  // See note in DirectSound implementation about GetDesktopWindow().\r
+  driverInfo.sysRef = GetForegroundWindow();\r
+}\r
+\r
+RtApiAsio :: ~RtApiAsio()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+  if ( coInitialized_ ) CoUninitialize();\r
+}\r
+\r
+unsigned int RtApiAsio :: getDeviceCount( void )\r
+{\r
+  return (unsigned int) drivers.asioGetNumDev();\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  // Get device ID\r
+  unsigned int nDevices = getDeviceCount();\r
+  if ( nDevices == 0 ) {\r
+    errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  // If a stream is already open, we cannot probe other devices.  Thus, use the saved results.\r
+  if ( stream_.state != STREAM_CLOSED ) {\r
+    if ( device >= devices_.size() ) {\r
+      errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";\r
+      error( RtAudioError::WARNING );\r
+      return info;\r
+    }\r
+    return devices_[ device ];\r
+  }\r
+\r
+  char driverName[32];\r
+  ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  info.name = driverName;\r
+\r
+  if ( !drivers.loadDriver( driverName ) ) {\r
+    errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  result = ASIOInit( &driverInfo );\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Determine the device channel information.\r
+  long inputChannels, outputChannels;\r
+  result = ASIOGetChannels( &inputChannels, &outputChannels );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  info.outputChannels = outputChannels;\r
+  info.inputChannels = inputChannels;\r
+  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
+    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+\r
+  // Determine the supported sample rates.\r
+  info.sampleRates.clear();\r
+  for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
+    result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );\r
+    if ( result == ASE_OK )\r
+      info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+  }\r
+\r
+  // Determine supported data types ... just check first channel and assume rest are the same.\r
+  ASIOChannelInfo channelInfo;\r
+  channelInfo.channel = 0;\r
+  channelInfo.isInput = true;\r
+  if ( info.inputChannels <= 0 ) channelInfo.isInput = false;\r
+  result = ASIOGetChannelInfo( &channelInfo );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  info.nativeFormats = 0;\r
+  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )\r
+    info.nativeFormats |= RTAUDIO_SINT16;\r
+  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )\r
+    info.nativeFormats |= RTAUDIO_SINT32;\r
+  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )\r
+    info.nativeFormats |= RTAUDIO_FLOAT32;\r
+  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )\r
+    info.nativeFormats |= RTAUDIO_FLOAT64;\r
+  else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )\r
+    info.nativeFormats |= RTAUDIO_SINT24;\r
+\r
+  if ( info.outputChannels > 0 )\r
+    if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;\r
+  if ( info.inputChannels > 0 )\r
+    if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;\r
+\r
+  info.probed = true;\r
+  drivers.removeCurrentDriver();\r
+  return info;\r
+}\r
+\r
+static void bufferSwitch( long index, ASIOBool /*processNow*/ )\r
+{\r
+  RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;\r
+  object->callbackEvent( index );\r
+}\r
+\r
+void RtApiAsio :: saveDeviceInfo( void )\r
+{\r
+  devices_.clear();\r
+\r
+  unsigned int nDevices = getDeviceCount();\r
+  devices_.resize( nDevices );\r
+  for ( unsigned int i=0; i<nDevices; i++ )\r
+    devices_[i] = getDeviceInfo( i );\r
+}\r
+\r
+bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                   unsigned int firstChannel, unsigned int sampleRate,\r
+                                   RtAudioFormat format, unsigned int *bufferSize,\r
+                                   RtAudio::StreamOptions *options )\r
+{\r
+  // For ASIO, a duplex stream MUST use the same driver.\r
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {\r
+    errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";\r
+    return FAILURE;\r
+  }\r
+\r
+  char driverName[32];\r
+  ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: unable to get driver name (" << getAsioErrorString( result ) << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Only load the driver once for duplex stream.\r
+  if ( mode != INPUT || stream_.mode != OUTPUT ) {\r
+    // The getDeviceInfo() function will not work when a stream is open\r
+    // because ASIO does not allow multiple devices to run at the same\r
+    // time.  Thus, we'll probe the system before opening a stream and\r
+    // save the results for use by getDeviceInfo().\r
+    this->saveDeviceInfo();\r
+\r
+    if ( !drivers.loadDriver( driverName ) ) {\r
+      errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    result = ASIOInit( &driverInfo );\r
+    if ( result != ASE_OK ) {\r
+      errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // Check the device channel count.\r
+  long inputChannels, outputChannels;\r
+  result = ASIOGetChannels( &inputChannels, &outputChannels );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||\r
+       ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  stream_.nDeviceChannels[mode] = channels;\r
+  stream_.nUserChannels[mode] = channels;\r
+  stream_.channelOffset[mode] = firstChannel;\r
+\r
+  // Verify the sample rate is supported.\r
+  result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Get the current sample rate\r
+  ASIOSampleRate currentRate;\r
+  result = ASIOGetSampleRate( &currentRate );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the sample rate only if necessary\r
+  if ( currentRate != sampleRate ) {\r
+    result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );\r
+    if ( result != ASE_OK ) {\r
+      drivers.removeCurrentDriver();\r
+      errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // Determine the driver data type.\r
+  ASIOChannelInfo channelInfo;\r
+  channelInfo.channel = 0;\r
+  if ( mode == OUTPUT ) channelInfo.isInput = false;\r
+  else channelInfo.isInput = true;\r
+  result = ASIOGetChannelInfo( &channelInfo );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Assuming WINDOWS host is always little-endian.\r
+  stream_.doByteSwap[mode] = false;\r
+  stream_.userFormat = format;\r
+  stream_.deviceFormat[mode] = 0;\r
+  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+    if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;\r
+  }\r
+  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+    if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;\r
+  }\r
+  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
+    if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;\r
+  }\r
+  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;\r
+    if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;\r
+  }\r
+  else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+    if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;\r
+  }\r
+\r
+  if ( stream_.deviceFormat[mode] == 0 ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the buffer size.  For a duplex stream, this will end up\r
+  // setting the buffer size based on the input constraints, which\r
+  // should be ok.\r
+  long minSize, maxSize, preferSize, granularity;\r
+  result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );\r
+  if ( result != ASE_OK ) {\r
+    drivers.removeCurrentDriver();\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+  else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+  else if ( granularity == -1 ) {\r
+    // Make sure bufferSize is a power of two.\r
+    int log2_of_min_size = 0;\r
+    int log2_of_max_size = 0;\r
+\r
+    for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
+      if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
+      if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
+    }\r
+\r
+    long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
+    int min_delta_num = log2_of_min_size;\r
+\r
+    for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
+      long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
+      if (current_delta < min_delta) {\r
+        min_delta = current_delta;\r
+        min_delta_num = i;\r
+      }\r
+    }\r
+\r
+    *bufferSize = ( (unsigned int)1 << min_delta_num );\r
+    if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+  }\r
+  else if ( granularity != 0 ) {\r
+    // Set to an even multiple of granularity, rounding up.\r
+    *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
+  }\r
+\r
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {\r
+    drivers.removeCurrentDriver();\r
+    errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";\r
+    return FAILURE;\r
+  }\r
+\r
+  stream_.bufferSize = *bufferSize;\r
+  stream_.nBuffers = 2;\r
+\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
+\r
+  // ASIO always uses non-interleaved buffers.\r
+  stream_.deviceInterleaved[mode] = false;\r
+\r
+  // Allocate, if necessary, our AsioHandle structure for the stream.\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  if ( handle == 0 ) {\r
+    try {\r
+      handle = new AsioHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      //if ( handle == NULL ) {    \r
+      drivers.removeCurrentDriver();\r
+      errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";\r
+      return FAILURE;\r
+    }\r
+    handle->bufferInfos = 0;\r
+\r
+    // Create a manual-reset event.\r
+    handle->condition = CreateEvent( NULL,   // no security\r
+                                     TRUE,   // manual-reset\r
+                                     FALSE,  // non-signaled initially\r
+                                     NULL ); // unnamed\r
+    stream_.apiHandle = (void *) handle;\r
+  }\r
+\r
+  // Create the ASIO internal buffers.  Since RtAudio sets up input\r
+  // and output separately, we'll have to dispose of previously\r
+  // created output buffers for a duplex stream.\r
+  long inputLatency, outputLatency;\r
+  if ( mode == INPUT && stream_.mode == OUTPUT ) {\r
+    ASIODisposeBuffers();\r
+    if ( handle->bufferInfos ) free( handle->bufferInfos );\r
+  }\r
+\r
+  // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.\r
+  bool buffersAllocated = false;\r
+  unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
+  handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );\r
+  if ( handle->bufferInfos == NULL ) {\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";\r
+    errorText_ = errorStream_.str();\r
+    goto error;\r
+  }\r
+\r
+  ASIOBufferInfo *infos;\r
+  infos = handle->bufferInfos;\r
+  for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {\r
+    infos->isInput = ASIOFalse;\r
+    infos->channelNum = i + stream_.channelOffset[0];\r
+    infos->buffers[0] = infos->buffers[1] = 0;\r
+  }\r
+  for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {\r
+    infos->isInput = ASIOTrue;\r
+    infos->channelNum = i + stream_.channelOffset[1];\r
+    infos->buffers[0] = infos->buffers[1] = 0;\r
+  }\r
+\r
+  // Set up the ASIO callback structure and create the ASIO data buffers.\r
+  asioCallbacks.bufferSwitch = &bufferSwitch;\r
+  asioCallbacks.sampleRateDidChange = &sampleRateChanged;\r
+  asioCallbacks.asioMessage = &asioMessages;\r
+  asioCallbacks.bufferSwitchTimeInfo = NULL;\r
+  result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";\r
+    errorText_ = errorStream_.str();\r
+    goto error;\r
+  }\r
+  buffersAllocated = true;\r
+\r
+  // Set flags for buffer conversion.\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+       stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate necessary internal buffers\r
+  unsigned long bufferBytes;\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.sampleRate = sampleRate;\r
+  stream_.device[mode] = device;\r
+  stream_.state = STREAM_STOPPED;\r
+  asioCallbackInfo = &stream_.callbackInfo;\r
+  stream_.callbackInfo.object = (void *) this;\r
+  if ( stream_.mode == OUTPUT && mode == INPUT )\r
+    // We had already set up an output stream.\r
+    stream_.mode = DUPLEX;\r
+  else\r
+    stream_.mode = mode;\r
+\r
+  // Determine device latencies\r
+  result = ASIOGetLatencies( &inputLatency, &outputLatency );\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING); // warn but don't fail\r
+  }\r
+  else {\r
+    stream_.latency[0] = outputLatency;\r
+    stream_.latency[1] = inputLatency;\r
+  }\r
+\r
+  // Setup the buffer conversion information structure.  We don't use\r
+  // buffers to do channel offsets, so we override that parameter\r
+  // here.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );\r
+\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( buffersAllocated )\r
+    ASIODisposeBuffers();\r
+  drivers.removeCurrentDriver();\r
+\r
+  if ( handle ) {\r
+    CloseHandle( handle->condition );\r
+    if ( handle->bufferInfos )\r
+      free( handle->bufferInfos );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiAsio :: closeStream()\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiAsio::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    stream_.state = STREAM_STOPPED;\r
+    ASIOStop();\r
+  }\r
+  ASIODisposeBuffers();\r
+  drivers.removeCurrentDriver();\r
+\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  if ( handle ) {\r
+    CloseHandle( handle->condition );\r
+    if ( handle->bufferInfos )\r
+      free( handle->bufferInfos );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+bool stopThreadCalled = false;\r
+\r
+void RtApiAsio :: startStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiAsio::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  ASIOError result = ASIOStart();\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device.";\r
+    errorText_ = errorStream_.str();\r
+    goto unlock;\r
+  }\r
+\r
+  handle->drainCounter = 0;\r
+  handle->internalDrain = false;\r
+  ResetEvent( handle->condition );\r
+  stream_.state = STREAM_RUNNING;\r
+  asioXRun = false;\r
+\r
+ unlock:\r
+  stopThreadCalled = false;\r
+\r
+  if ( result == ASE_OK ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiAsio :: stopStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( handle->drainCounter == 0 ) {\r
+      handle->drainCounter = 2;\r
+      WaitForSingleObject( handle->condition, INFINITE );  // block until signaled\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+  ASIOError result = ASIOStop();\r
+  if ( result != ASE_OK ) {\r
+    errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device.";\r
+    errorText_ = errorStream_.str();\r
+  }\r
+\r
+  if ( result == ASE_OK ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiAsio :: abortStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // The following lines were commented-out because some behavior was\r
+  // noted where the device buffers need to be zeroed to avoid\r
+  // continuing sound, even when the device buffers are completely\r
+  // disposed.  So now, calling abort is the same as calling stop.\r
+  // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  // handle->drainCounter = 2;\r
+  stopStream();\r
+}\r
+\r
+// This function will be called by a spawned thread when the user\r
+// callback function signals that the stream should be stopped or\r
+// aborted.  It is necessary to handle it this way because the\r
+// callbackEvent() function must return before the ASIOStop()\r
+// function will return.\r
+static unsigned __stdcall asioStopStream( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiAsio *object = (RtApiAsio *) info->object;\r
+\r
+  object->stopStream();\r
+  _endthreadex( 0 );\r
+  return 0;\r
+}\r
+\r
+bool RtApiAsio :: callbackEvent( long bufferIndex )\r
+{\r
+  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return FAILURE;\r
+  }\r
+\r
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+\r
+  // Check if we were draining the stream and signal if finished.\r
+  if ( handle->drainCounter > 3 ) {\r
+\r
+    stream_.state = STREAM_STOPPING;\r
+    if ( handle->internalDrain == false )\r
+      SetEvent( handle->condition );\r
+    else { // spawn a thread to stop the stream\r
+      unsigned threadId;\r
+      stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,\r
+                                                    &stream_.callbackInfo, 0, &threadId );\r
+    }\r
+    return SUCCESS;\r
+  }\r
+\r
+  // Invoke user callback to get fresh output data UNLESS we are\r
+  // draining stream.\r
+  if ( handle->drainCounter == 0 ) {\r
+    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
+    double streamTime = getStreamTime();\r
+    RtAudioStreamStatus status = 0;\r
+    if ( stream_.mode != INPUT && asioXRun == true ) {\r
+      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+      asioXRun = false;\r
+    }\r
+    if ( stream_.mode != OUTPUT && asioXRun == true ) {\r
+      status |= RTAUDIO_INPUT_OVERFLOW;\r
+      asioXRun = false;\r
+    }\r
+    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                                     stream_.bufferSize, streamTime, status, info->userData );\r
+    if ( cbReturnValue == 2 ) {\r
+      stream_.state = STREAM_STOPPING;\r
+      handle->drainCounter = 2;\r
+      unsigned threadId;\r
+      stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,\r
+                                                    &stream_.callbackInfo, 0, &threadId );\r
+      return SUCCESS;\r
+    }\r
+    else if ( cbReturnValue == 1 ) {\r
+      handle->drainCounter = 1;\r
+      handle->internalDrain = true;\r
+    }\r
+  }\r
+\r
+  unsigned int nChannels, bufferBytes, i, j;\r
+  nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );\r
+\r
+    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
+\r
+      for ( i=0, j=0; i<nChannels; i++ ) {\r
+        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
+          memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes );\r
+      }\r
+\r
+    }\r
+    else if ( stream_.doConvertBuffer[0] ) {\r
+\r
+      convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+      if ( stream_.doByteSwap[0] )\r
+        byteSwapBuffer( stream_.deviceBuffer,\r
+                        stream_.bufferSize * stream_.nDeviceChannels[0],\r
+                        stream_.deviceFormat[0] );\r
+\r
+      for ( i=0, j=0; i<nChannels; i++ ) {\r
+        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
+          memcpy( handle->bufferInfos[i].buffers[bufferIndex],\r
+                  &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );\r
+      }\r
+\r
+    }\r
+    else {\r
+\r
+      if ( stream_.doByteSwap[0] )\r
+        byteSwapBuffer( stream_.userBuffer[0],\r
+                        stream_.bufferSize * stream_.nUserChannels[0],\r
+                        stream_.userFormat );\r
+\r
+      for ( i=0, j=0; i<nChannels; i++ ) {\r
+        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
+          memcpy( handle->bufferInfos[i].buffers[bufferIndex],\r
+                  &stream_.userBuffer[0][bufferBytes*j++], bufferBytes );\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+  // Don't bother draining input\r
+  if ( handle->drainCounter ) {\r
+    handle->drainCounter++;\r
+    goto unlock;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);\r
+\r
+    if (stream_.doConvertBuffer[1]) {\r
+\r
+      // Always interleave ASIO input data.\r
+      for ( i=0, j=0; i<nChannels; i++ ) {\r
+        if ( handle->bufferInfos[i].isInput == ASIOTrue )\r
+          memcpy( &stream_.deviceBuffer[j++*bufferBytes],\r
+                  handle->bufferInfos[i].buffers[bufferIndex],\r
+                  bufferBytes );\r
+      }\r
+\r
+      if ( stream_.doByteSwap[1] )\r
+        byteSwapBuffer( stream_.deviceBuffer,\r
+                        stream_.bufferSize * stream_.nDeviceChannels[1],\r
+                        stream_.deviceFormat[1] );\r
+      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
+\r
+    }\r
+    else {\r
+      for ( i=0, j=0; i<nChannels; i++ ) {\r
+        if ( handle->bufferInfos[i].isInput == ASIOTrue ) {\r
+          memcpy( &stream_.userBuffer[1][bufferBytes*j++],\r
+                  handle->bufferInfos[i].buffers[bufferIndex],\r
+                  bufferBytes );\r
+        }\r
+      }\r
+\r
+      if ( stream_.doByteSwap[1] )\r
+        byteSwapBuffer( stream_.userBuffer[1],\r
+                        stream_.bufferSize * stream_.nUserChannels[1],\r
+                        stream_.userFormat );\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  // The following call was suggested by Malte Clasen.  While the API\r
+  // documentation indicates it should not be required, some device\r
+  // drivers apparently do not function correctly without it.\r
+  ASIOOutputReady();\r
+\r
+  RtApi::tickStreamTime();\r
+  return SUCCESS;\r
+}\r
+\r
+static void sampleRateChanged( ASIOSampleRate sRate )\r
+{\r
+  // The ASIO documentation says that this usually only happens during\r
+  // external sync.  Audio processing is not stopped by the driver,\r
+  // actual sample rate might not have even changed, maybe only the\r
+  // sample rate status of an AES/EBU or S/PDIF digital input at the\r
+  // audio device.\r
+\r
+  RtApi *object = (RtApi *) asioCallbackInfo->object;\r
+  try {\r
+    object->stopStream();\r
+  }\r
+  catch ( RtAudioError &exception ) {\r
+    std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;\r
+    return;\r
+  }\r
+\r
+  std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;\r
+}\r
+\r
+static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )\r
+{\r
+  long ret = 0;\r
+\r
+  switch( selector ) {\r
+  case kAsioSelectorSupported:\r
+    if ( value == kAsioResetRequest\r
+         || value == kAsioEngineVersion\r
+         || value == kAsioResyncRequest\r
+         || value == kAsioLatenciesChanged\r
+         // The following three were added for ASIO 2.0, you don't\r
+         // necessarily have to support them.\r
+         || value == kAsioSupportsTimeInfo\r
+         || value == kAsioSupportsTimeCode\r
+         || value == kAsioSupportsInputMonitor)\r
+      ret = 1L;\r
+    break;\r
+  case kAsioResetRequest:\r
+    // Defer the task and perform the reset of the driver during the\r
+    // next "safe" situation.  You cannot reset the driver right now,\r
+    // as this code is called from the driver.  Reset the driver is\r
+    // done by completely destruct is. I.e. ASIOStop(),\r
+    // ASIODisposeBuffers(), Destruction Afterwards you initialize the\r
+    // driver again.\r
+    std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl;\r
+    ret = 1L;\r
+    break;\r
+  case kAsioResyncRequest:\r
+    // This informs the application that the driver encountered some\r
+    // non-fatal data loss.  It is used for synchronization purposes\r
+    // of different media.  Added mainly to work around the Win16Mutex\r
+    // problems in Windows 95/98 with the Windows Multimedia system,\r
+    // which could lose data because the Mutex was held too long by\r
+    // another thread.  However a driver can issue it in other\r
+    // situations, too.\r
+    // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl;\r
+    asioXRun = true;\r
+    ret = 1L;\r
+    break;\r
+  case kAsioLatenciesChanged:\r
+    // This will inform the host application that the drivers were\r
+    // latencies changed.  Beware, it this does not mean that the\r
+    // buffer sizes have changed!  You might need to update internal\r
+    // delay data.\r
+    std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl;\r
+    ret = 1L;\r
+    break;\r
+  case kAsioEngineVersion:\r
+    // Return the supported ASIO version of the host application.  If\r
+    // a host application does not implement this selector, ASIO 1.0\r
+    // is assumed by the driver.\r
+    ret = 2L;\r
+    break;\r
+  case kAsioSupportsTimeInfo:\r
+    // Informs the driver whether the\r
+    // asioCallbacks.bufferSwitchTimeInfo() callback is supported.\r
+    // For compatibility with ASIO 1.0 drivers the host application\r
+    // should always support the "old" bufferSwitch method, too.\r
+    ret = 0;\r
+    break;\r
+  case kAsioSupportsTimeCode:\r
+    // Informs the driver whether application is interested in time\r
+    // code info.  If an application does not need to know about time\r
+    // code, the driver has less work to do.\r
+    ret = 0;\r
+    break;\r
+  }\r
+  return ret;\r
+}\r
+\r
+static const char* getAsioErrorString( ASIOError result )\r
+{\r
+  struct Messages \r
+  {\r
+    ASIOError value;\r
+    const char*message;\r
+  };\r
+\r
+  static const Messages m[] = \r
+    {\r
+      {   ASE_NotPresent,    "Hardware input or output is not present or available." },\r
+      {   ASE_HWMalfunction,  "Hardware is malfunctioning." },\r
+      {   ASE_InvalidParameter, "Invalid input parameter." },\r
+      {   ASE_InvalidMode,      "Invalid mode." },\r
+      {   ASE_SPNotAdvancing,     "Sample position not advancing." },\r
+      {   ASE_NoClock,            "Sample clock or rate cannot be determined or is not present." },\r
+      {   ASE_NoMemory,           "Not enough memory to complete the request." }\r
+    };\r
+\r
+  for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )\r
+    if ( m[i].value == result ) return m[i].message;\r
+\r
+  return "Unknown error.";\r
+}\r
+\r
+//******************** End of __WINDOWS_ASIO__ *********************//\r
+#endif\r
+\r
+\r
+#if defined(__WINDOWS_WASAPI__) // Windows WASAPI API\r
+\r
+// Authored by Marcus Tomlinson <themarcustomlinson@gmail.com>, April 2014\r
+// - Introduces support for the Windows WASAPI API\r
+// - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required\r
+// - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface\r
+// - Includes automatic internal conversion of sample rate and buffer size between hardware and the user\r
+\r
+#ifndef INITGUID\r
+  #define INITGUID\r
+#endif\r
+#include <audioclient.h>\r
+#include <avrt.h>\r
+#include <mmdeviceapi.h>\r
+#include <functiondiscoverykeys_devpkey.h>\r
+\r
+//=============================================================================\r
+\r
+#define SAFE_RELEASE( objectPtr )\\r
+if ( objectPtr )\\r
+{\\r
+  objectPtr->Release();\\r
+  objectPtr = NULL;\\r
+}\r
+\r
+typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex );\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+// WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size.\r
+// Therefore we must perform all necessary conversions to user buffers in order to satisfy these\r
+// requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to\r
+// provide intermediate storage for read / write synchronization.\r
+class WasapiBuffer\r
+{\r
+public:\r
+  WasapiBuffer()\r
+    : buffer_( NULL ),\r
+      bufferSize_( 0 ),\r
+      inIndex_( 0 ),\r
+      outIndex_( 0 ) {}\r
+\r
+  ~WasapiBuffer() {\r
+    delete buffer_;\r
+  }\r
+\r
+  // sets the length of the internal ring buffer\r
+  void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {\r
+    delete buffer_;\r
+\r
+    buffer_ = ( char* ) calloc( bufferSize, formatBytes );\r
+\r
+    bufferSize_ = bufferSize;\r
+    inIndex_ = 0;\r
+    outIndex_ = 0;\r
+  }\r
+\r
+  // attempt to push a buffer into the ring buffer at the current "in" index\r
+  bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )\r
+  {\r
+    if ( !buffer ||                 // incoming buffer is NULL\r
+         bufferSize == 0 ||         // incoming buffer has no data\r
+         bufferSize > bufferSize_ ) // incoming buffer too large\r
+    {\r
+      return false;\r
+    }\r
+\r
+    unsigned int relOutIndex = outIndex_;\r
+    unsigned int inIndexEnd = inIndex_ + bufferSize;\r
+    if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) {\r
+      relOutIndex += bufferSize_;\r
+    }\r
+\r
+    // "in" index can end on the "out" index but cannot begin at it\r
+    if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {\r
+      return false; // not enough space between "in" index and "out" index\r
+    }\r
+\r
+    // copy buffer from external to internal\r
+    int fromZeroSize = inIndex_ + bufferSize - bufferSize_;\r
+    fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;\r
+    int fromInSize = bufferSize - fromZeroSize;\r
+\r
+    switch( format )\r
+      {\r
+      case RTAUDIO_SINT8:\r
+        memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) );\r
+        memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) );\r
+        break;\r
+      case RTAUDIO_SINT16:\r
+        memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) );\r
+        memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) );\r
+        break;\r
+      case RTAUDIO_SINT24:\r
+        memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) );\r
+        memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) );\r
+        break;\r
+      case RTAUDIO_SINT32:\r
+        memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) );\r
+        memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) );\r
+        break;\r
+      case RTAUDIO_FLOAT32:\r
+        memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) );\r
+        memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) );\r
+        break;\r
+      case RTAUDIO_FLOAT64:\r
+        memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) );\r
+        memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) );\r
+        break;\r
+    }\r
+\r
+    // update "in" index\r
+    inIndex_ += bufferSize;\r
+    inIndex_ %= bufferSize_;\r
+\r
+    return true;\r
+  }\r
+\r
+  // attempt to pull a buffer from the ring buffer from the current "out" index\r
+  bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )\r
+  {\r
+    if ( !buffer ||                 // incoming buffer is NULL\r
+         bufferSize == 0 ||         // incoming buffer has no data\r
+         bufferSize > bufferSize_ ) // incoming buffer too large\r
+    {\r
+      return false;\r
+    }\r
+\r
+    unsigned int relInIndex = inIndex_;\r
+    unsigned int outIndexEnd = outIndex_ + bufferSize;\r
+    if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) {\r
+      relInIndex += bufferSize_;\r
+    }\r
+\r
+    // "out" index can begin at and end on the "in" index\r
+    if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {\r
+      return false; // not enough space between "out" index and "in" index\r
+    }\r
+\r
+    // copy buffer from internal to external\r
+    int fromZeroSize = outIndex_ + bufferSize - bufferSize_;\r
+    fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;\r
+    int fromOutSize = bufferSize - fromZeroSize;\r
+\r
+    switch( format )\r
+    {\r
+      case RTAUDIO_SINT8:\r
+        memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) );\r
+        memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) );\r
+        break;\r
+      case RTAUDIO_SINT16:\r
+        memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) );\r
+        memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) );\r
+        break;\r
+      case RTAUDIO_SINT24:\r
+        memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) );\r
+        memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) );\r
+        break;\r
+      case RTAUDIO_SINT32:\r
+        memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) );\r
+        memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) );\r
+        break;\r
+      case RTAUDIO_FLOAT32:\r
+        memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) );\r
+        memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) );\r
+        break;\r
+      case RTAUDIO_FLOAT64:\r
+        memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) );\r
+        memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) );\r
+        break;\r
+    }\r
+\r
+    // update "out" index\r
+    outIndex_ += bufferSize;\r
+    outIndex_ %= bufferSize_;\r
+\r
+    return true;\r
+  }\r
+\r
+private:\r
+  char* buffer_;\r
+  unsigned int bufferSize_;\r
+  unsigned int inIndex_;\r
+  unsigned int outIndex_;\r
+};\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate\r
+// between HW and the user. The convertBufferWasapi function is used to perform this conversion\r
+// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.\r
+// This sample rate converter favors speed over quality, and works best with conversions between\r
+// one rate and its multiple.\r
+void convertBufferWasapi( char* outBuffer,\r
+                          const char* inBuffer,\r
+                          const unsigned int& channelCount,\r
+                          const unsigned int& inSampleRate,\r
+                          const unsigned int& outSampleRate,\r
+                          const unsigned int& inSampleCount,\r
+                          unsigned int& outSampleCount,\r
+                          const RtAudioFormat& format )\r
+{\r
+  // calculate the new outSampleCount and relative sampleStep\r
+  float sampleRatio = ( float ) outSampleRate / inSampleRate;\r
+  float sampleStep = 1.0f / sampleRatio;\r
+  float inSampleFraction = 0.0f;\r
+\r
+  outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );\r
+\r
+  // frame-by-frame, copy each relative input sample into it's corresponding output sample\r
+  for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )\r
+  {\r
+    unsigned int inSample = ( unsigned int ) inSampleFraction;\r
+\r
+    switch ( format )\r
+    {\r
+      case RTAUDIO_SINT8:\r
+        memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );\r
+        break;\r
+      case RTAUDIO_SINT16:\r
+        memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );\r
+        break;\r
+      case RTAUDIO_SINT24:\r
+        memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );\r
+        break;\r
+      case RTAUDIO_SINT32:\r
+        memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );\r
+        break;\r
+      case RTAUDIO_FLOAT32:\r
+        memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );\r
+        break;\r
+      case RTAUDIO_FLOAT64:\r
+        memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );\r
+        break;\r
+    }\r
+\r
+    // jump to next in sample\r
+    inSampleFraction += sampleStep;\r
+  }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+// A structure to hold various information related to the WASAPI implementation.\r
+struct WasapiHandle\r
+{\r
+  IAudioClient* captureAudioClient;\r
+  IAudioClient* renderAudioClient;\r
+  IAudioCaptureClient* captureClient;\r
+  IAudioRenderClient* renderClient;\r
+  HANDLE captureEvent;\r
+  HANDLE renderEvent;\r
+\r
+  WasapiHandle()\r
+  : captureAudioClient( NULL ),\r
+    renderAudioClient( NULL ),\r
+    captureClient( NULL ),\r
+    renderClient( NULL ),\r
+    captureEvent( NULL ),\r
+    renderEvent( NULL ) {}\r
+};\r
+\r
+//=============================================================================\r
+\r
+RtApiWasapi::RtApiWasapi()\r
+  : coInitialized_( false ), deviceEnumerator_( NULL )\r
+{\r
+  // WASAPI can run either apartment or multi-threaded\r
+  HRESULT hr = CoInitialize( NULL );\r
+  if ( !FAILED( hr ) )\r
+    coInitialized_ = true;\r
+\r
+  // Instantiate device enumerator\r
+  hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,\r
+                         CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),\r
+                         ( void** ) &deviceEnumerator_ );\r
+\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";\r
+    error( RtAudioError::DRIVER_ERROR );\r
+  }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+RtApiWasapi::~RtApiWasapi()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED )\r
+    closeStream();\r
+\r
+  SAFE_RELEASE( deviceEnumerator_ );\r
+\r
+  // If this object previously called CoInitialize()\r
+  if ( coInitialized_ )\r
+    CoUninitialize();\r
+}\r
+\r
+//=============================================================================\r
+\r
+unsigned int RtApiWasapi::getDeviceCount( void )\r
+{\r
+  unsigned int captureDeviceCount = 0;\r
+  unsigned int renderDeviceCount = 0;\r
+\r
+  IMMDeviceCollection* captureDevices = NULL;\r
+  IMMDeviceCollection* renderDevices = NULL;\r
+\r
+  // Count capture devices\r
+  errorText_.clear();\r
+  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = captureDevices->GetCount( &captureDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";\r
+    goto Exit;\r
+  }\r
+\r
+  // Count render devices\r
+  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = renderDevices->GetCount( &renderDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";\r
+    goto Exit;\r
+  }\r
+\r
+Exit:\r
+  // release all references\r
+  SAFE_RELEASE( captureDevices );\r
+  SAFE_RELEASE( renderDevices );\r
+\r
+  if ( errorText_.empty() )\r
+    return captureDeviceCount + renderDeviceCount;\r
+\r
+  error( RtAudioError::DRIVER_ERROR );\r
+  return 0;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  unsigned int captureDeviceCount = 0;\r
+  unsigned int renderDeviceCount = 0;\r
+  std::wstring deviceName;\r
+  std::string defaultDeviceName;\r
+  bool isCaptureDevice = false;\r
+\r
+  PROPVARIANT deviceNameProp;\r
+  PROPVARIANT defaultDeviceNameProp;\r
+\r
+  IMMDeviceCollection* captureDevices = NULL;\r
+  IMMDeviceCollection* renderDevices = NULL;\r
+  IMMDevice* devicePtr = NULL;\r
+  IMMDevice* defaultDevicePtr = NULL;\r
+  IAudioClient* audioClient = NULL;\r
+  IPropertyStore* devicePropStore = NULL;\r
+  IPropertyStore* defaultDevicePropStore = NULL;\r
+\r
+  WAVEFORMATEX* deviceFormat = NULL;\r
+  WAVEFORMATEX* closestMatchFormat = NULL;\r
+\r
+  // probed\r
+  info.probed = false;\r
+\r
+  // Count capture devices\r
+  errorText_.clear();\r
+  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
+  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = captureDevices->GetCount( &captureDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";\r
+    goto Exit;\r
+  }\r
+\r
+  // Count render devices\r
+  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = renderDevices->GetCount( &renderDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";\r
+    goto Exit;\r
+  }\r
+\r
+  // validate device index\r
+  if ( device >= captureDeviceCount + renderDeviceCount ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";\r
+    errorType = RtAudioError::INVALID_USE;\r
+    goto Exit;\r
+  }\r
+\r
+  // determine whether index falls within capture or render devices\r
+  if ( device >= renderDeviceCount ) {\r
+    hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";\r
+      goto Exit;\r
+    }\r
+    isCaptureDevice = true;\r
+  }\r
+  else {\r
+    hr = renderDevices->Item( device, &devicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";\r
+      goto Exit;\r
+    }\r
+    isCaptureDevice = false;\r
+  }\r
+\r
+  // get default device name\r
+  if ( isCaptureDevice ) {\r
+    hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";\r
+      goto Exit;\r
+    }\r
+  }\r
+  else {\r
+    hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";\r
+    goto Exit;\r
+  }\r
+  PropVariantInit( &defaultDeviceNameProp );\r
+\r
+  hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";\r
+    goto Exit;\r
+  }\r
+\r
+  deviceName = defaultDeviceNameProp.pwszVal;\r
+  defaultDeviceName = std::string( deviceName.begin(), deviceName.end() );\r
+\r
+  // name\r
+  hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";\r
+    goto Exit;\r
+  }\r
+\r
+  PropVariantInit( &deviceNameProp );\r
+\r
+  hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";\r
+    goto Exit;\r
+  }\r
+\r
+  deviceName = deviceNameProp.pwszVal;\r
+  info.name = std::string( deviceName.begin(), deviceName.end() );\r
+\r
+  // is default\r
+  if ( isCaptureDevice ) {\r
+    info.isDefaultInput = info.name == defaultDeviceName;\r
+    info.isDefaultOutput = false;\r
+  }\r
+  else {\r
+    info.isDefaultInput = false;\r
+    info.isDefaultOutput = info.name == defaultDeviceName;\r
+  }\r
+\r
+  // channel count\r
+  hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = audioClient->GetMixFormat( &deviceFormat );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";\r
+    goto Exit;\r
+  }\r
+\r
+  if ( isCaptureDevice ) {\r
+    info.inputChannels = deviceFormat->nChannels;\r
+    info.outputChannels = 0;\r
+    info.duplexChannels = 0;\r
+  }\r
+  else {\r
+    info.inputChannels = 0;\r
+    info.outputChannels = deviceFormat->nChannels;\r
+    info.duplexChannels = 0;\r
+  }\r
+\r
+  // sample rates\r
+  info.sampleRates.clear();\r
+\r
+  // allow support for all sample rates as we have a built-in sample rate converter\r
+  for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {\r
+    info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+  }\r
+\r
+  // native format\r
+  info.nativeFormats = 0;\r
+\r
+  if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||\r
+       ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&\r
+         ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )\r
+  {\r
+    if ( deviceFormat->wBitsPerSample == 32 ) {\r
+      info.nativeFormats |= RTAUDIO_FLOAT32;\r
+    }\r
+    else if ( deviceFormat->wBitsPerSample == 64 ) {\r
+      info.nativeFormats |= RTAUDIO_FLOAT64;\r
+    }\r
+  }\r
+  else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||\r
+           ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&\r
+             ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )\r
+  {\r
+    if ( deviceFormat->wBitsPerSample == 8 ) {\r
+      info.nativeFormats |= RTAUDIO_SINT8;\r
+    }\r
+    else if ( deviceFormat->wBitsPerSample == 16 ) {\r
+      info.nativeFormats |= RTAUDIO_SINT16;\r
+    }\r
+    else if ( deviceFormat->wBitsPerSample == 24 ) {\r
+      info.nativeFormats |= RTAUDIO_SINT24;\r
+    }\r
+    else if ( deviceFormat->wBitsPerSample == 32 ) {\r
+      info.nativeFormats |= RTAUDIO_SINT32;\r
+    }\r
+  }\r
+\r
+  // probed\r
+  info.probed = true;\r
+\r
+Exit:\r
+  // release all references\r
+  PropVariantClear( &deviceNameProp );\r
+  PropVariantClear( &defaultDeviceNameProp );\r
+\r
+  SAFE_RELEASE( captureDevices );\r
+  SAFE_RELEASE( renderDevices );\r
+  SAFE_RELEASE( devicePtr );\r
+  SAFE_RELEASE( defaultDevicePtr );\r
+  SAFE_RELEASE( audioClient );\r
+  SAFE_RELEASE( devicePropStore );\r
+  SAFE_RELEASE( defaultDevicePropStore );\r
+\r
+  CoTaskMemFree( deviceFormat );\r
+  CoTaskMemFree( closestMatchFormat );\r
+\r
+  if ( !errorText_.empty() )\r
+    error( errorType );\r
+  return info;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+unsigned int RtApiWasapi::getDefaultOutputDevice( void )\r
+{\r
+  for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {\r
+    if ( getDeviceInfo( i ).isDefaultOutput ) {\r
+      return i;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+unsigned int RtApiWasapi::getDefaultInputDevice( void )\r
+{\r
+  for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {\r
+    if ( getDeviceInfo( i ).isDefaultInput ) {\r
+      return i;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+void RtApiWasapi::closeStream( void )\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiWasapi::closeStream: No open stream to close.";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  if ( stream_.state != STREAM_STOPPED )\r
+    stopStream();\r
+\r
+  // clean up stream memory\r
+  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )\r
+  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )\r
+\r
+  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )\r
+  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )\r
+\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )\r
+    CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );\r
+\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )\r
+    CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );\r
+\r
+  delete ( WasapiHandle* ) stream_.apiHandle;\r
+  stream_.apiHandle = NULL;\r
+\r
+  for ( int i = 0; i < 2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  // update stream state\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+void RtApiWasapi::startStream( void )\r
+{\r
+  verifyStream();\r
+\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiWasapi::startStream: The stream is already running.";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // update stream state\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+  // create WASAPI stream thread\r
+  stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );\r
+\r
+  if ( !stream_.callbackInfo.thread ) {\r
+    errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";\r
+    error( RtAudioError::THREAD_ERROR );\r
+  }\r
+  else {\r
+    SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );\r
+    ResumeThread( ( void* ) stream_.callbackInfo.thread );\r
+  }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+void RtApiWasapi::stopStream( void )\r
+{\r
+  verifyStream();\r
+\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // inform stream thread by setting stream state to STREAM_STOPPING\r
+  stream_.state = STREAM_STOPPING;\r
+\r
+  // wait until stream thread is stopped\r
+  while( stream_.state != STREAM_STOPPED ) {\r
+    Sleep( 1 );\r
+  }\r
+\r
+  // Wait for the last buffer to play before stopping.\r
+  Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );\r
+\r
+  // stop capture client if applicable\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
+    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";\r
+      error( RtAudioError::DRIVER_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  // stop render client if applicable\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
+    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";\r
+      error( RtAudioError::DRIVER_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  // close thread handle\r
+  if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
+    errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";\r
+    error( RtAudioError::THREAD_ERROR );\r
+    return;\r
+  }\r
+\r
+  stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+void RtApiWasapi::abortStream( void )\r
+{\r
+  verifyStream();\r
+\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // inform stream thread by setting stream state to STREAM_STOPPING\r
+  stream_.state = STREAM_STOPPING;\r
+\r
+  // wait until stream thread is stopped\r
+  while ( stream_.state != STREAM_STOPPED ) {\r
+    Sleep( 1 );\r
+  }\r
+\r
+  // stop capture client if applicable\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
+    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";\r
+      error( RtAudioError::DRIVER_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  // stop render client if applicable\r
+  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
+    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";\r
+      error( RtAudioError::DRIVER_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  // close thread handle\r
+  if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
+    errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";\r
+    error( RtAudioError::THREAD_ERROR );\r
+    return;\r
+  }\r
+\r
+  stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                   unsigned int firstChannel, unsigned int sampleRate,\r
+                                   RtAudioFormat format, unsigned int* bufferSize,\r
+                                   RtAudio::StreamOptions* options )\r
+{\r
+  bool methodResult = FAILURE;\r
+  unsigned int captureDeviceCount = 0;\r
+  unsigned int renderDeviceCount = 0;\r
+\r
+  IMMDeviceCollection* captureDevices = NULL;\r
+  IMMDeviceCollection* renderDevices = NULL;\r
+  IMMDevice* devicePtr = NULL;\r
+  WAVEFORMATEX* deviceFormat = NULL;\r
+  unsigned int bufferBytes;\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+  // create API Handle if not already created\r
+  if ( !stream_.apiHandle )\r
+    stream_.apiHandle = ( void* ) new WasapiHandle();\r
+\r
+  // Count capture devices\r
+  errorText_.clear();\r
+  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
+  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = captureDevices->GetCount( &captureDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";\r
+    goto Exit;\r
+  }\r
+\r
+  // Count render devices\r
+  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";\r
+    goto Exit;\r
+  }\r
+\r
+  hr = renderDevices->GetCount( &renderDeviceCount );\r
+  if ( FAILED( hr ) ) {\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";\r
+    goto Exit;\r
+  }\r
+\r
+  // validate device index\r
+  if ( device >= captureDeviceCount + renderDeviceCount ) {\r
+    errorType = RtAudioError::INVALID_USE;\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";\r
+    goto Exit;\r
+  }\r
+\r
+  // determine whether index falls within capture or render devices\r
+  if ( device >= renderDeviceCount ) {\r
+    if ( mode != INPUT ) {\r
+      errorType = RtAudioError::INVALID_USE;\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";\r
+      goto Exit;\r
+    }\r
+\r
+    // retrieve captureAudioClient from devicePtr\r
+    IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;\r
+\r
+    hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";\r
+      goto Exit;\r
+    }\r
+\r
+    hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
+                              NULL, ( void** ) &captureAudioClient );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
+      goto Exit;\r
+    }\r
+\r
+    hr = captureAudioClient->GetMixFormat( &deviceFormat );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
+      goto Exit;\r
+    }\r
+\r
+    stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
+    captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
+  }\r
+  else {\r
+    if ( mode != OUTPUT ) {\r
+      errorType = RtAudioError::INVALID_USE;\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";\r
+      goto Exit;\r
+    }\r
+\r
+    // retrieve renderAudioClient from devicePtr\r
+    IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;\r
+\r
+    hr = renderDevices->Item( device, &devicePtr );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";\r
+      goto Exit;\r
+    }\r
+\r
+    hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
+                              NULL, ( void** ) &renderAudioClient );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
+      goto Exit;\r
+    }\r
+\r
+    hr = renderAudioClient->GetMixFormat( &deviceFormat );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
+      goto Exit;\r
+    }\r
+\r
+    stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
+    renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
+  }\r
+\r
+  // fill stream data\r
+  if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||\r
+       ( stream_.mode == INPUT && mode == OUTPUT ) ) {\r
+    stream_.mode = DUPLEX;\r
+  }\r
+  else {\r
+    stream_.mode = mode;\r
+  }\r
+\r
+  stream_.device[mode] = device;\r
+  stream_.doByteSwap[mode] = false;\r
+  stream_.sampleRate = sampleRate;\r
+  stream_.bufferSize = *bufferSize;\r
+  stream_.nBuffers = 1;\r
+  stream_.nUserChannels[mode] = channels;\r
+  stream_.channelOffset[mode] = firstChannel;\r
+  stream_.userFormat = format;\r
+  stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;\r
+\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED )\r
+    stream_.userInterleaved = false;\r
+  else\r
+    stream_.userInterleaved = true;\r
+  stream_.deviceInterleaved[mode] = true;\r
+\r
+  // Set flags for buffer conversion.\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] ||\r
+       stream_.nUserChannels != stream_.nDeviceChannels )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+            stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  if ( stream_.doConvertBuffer[mode] )\r
+    setConvertInfo( mode, 0 );\r
+\r
+  // Allocate necessary internal buffers\r
+  bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
+\r
+  stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );\r
+  if ( !stream_.userBuffer[mode] ) {\r
+    errorType = RtAudioError::MEMORY_ERROR;\r
+    errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";\r
+    goto Exit;\r
+  }\r
+\r
+  if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )\r
+    stream_.callbackInfo.priority = 15;\r
+  else\r
+    stream_.callbackInfo.priority = 0;\r
+\r
+  ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback\r
+  ///! TODO: RTAUDIO_HOG_DEVICE       // Exclusive mode\r
+\r
+  methodResult = SUCCESS;\r
+\r
+Exit:\r
+  //clean up\r
+  SAFE_RELEASE( captureDevices );\r
+  SAFE_RELEASE( renderDevices );\r
+  SAFE_RELEASE( devicePtr );\r
+  CoTaskMemFree( deviceFormat );\r
+\r
+  // if method failed, close the stream\r
+  if ( methodResult == FAILURE )\r
+    closeStream();\r
+\r
+  if ( !errorText_.empty() )\r
+    error( errorType );\r
+  return methodResult;\r
+}\r
+\r
+//=============================================================================\r
+\r
+DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )\r
+{\r
+  if ( wasapiPtr )\r
+    ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();\r
+\r
+  return 0;\r
+}\r
+\r
+DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )\r
+{\r
+  if ( wasapiPtr )\r
+    ( ( RtApiWasapi* ) wasapiPtr )->stopStream();\r
+\r
+  return 0;\r
+}\r
+\r
+DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )\r
+{\r
+  if ( wasapiPtr )\r
+    ( ( RtApiWasapi* ) wasapiPtr )->abortStream();\r
+\r
+  return 0;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+\r
+void RtApiWasapi::wasapiThread()\r
+{\r
+  // as this is a new thread, we must CoInitialize it\r
+  CoInitialize( NULL );\r
+\r
+  HRESULT hr;\r
+\r
+  IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;\r
+  IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;\r
+  IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;\r
+  IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;\r
+  HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;\r
+  HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;\r
+\r
+  WAVEFORMATEX* captureFormat = NULL;\r
+  WAVEFORMATEX* renderFormat = NULL;\r
+  float captureSrRatio = 0.0f;\r
+  float renderSrRatio = 0.0f;\r
+  WasapiBuffer captureBuffer;\r
+  WasapiBuffer renderBuffer;\r
+\r
+  // declare local stream variables\r
+  RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;\r
+  BYTE* streamBuffer = NULL;\r
+  unsigned long captureFlags = 0;\r
+  unsigned int bufferFrameCount = 0;\r
+  unsigned int numFramesPadding = 0;\r
+  unsigned int convBufferSize = 0;\r
+  bool callbackPushed = false;\r
+  bool callbackPulled = false;\r
+  bool callbackStopped = false;\r
+  int callbackResult = 0;\r
+\r
+  // convBuffer is used to store converted buffers between WASAPI and the user\r
+  char* convBuffer = NULL;\r
+  unsigned int convBuffSize = 0;\r
+  unsigned int deviceBuffSize = 0;\r
+\r
+  errorText_.clear();\r
+  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
+\r
+  // Attempt to assign "Pro Audio" characteristic to thread\r
+  HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );\r
+  if ( AvrtDll ) {\r
+    DWORD taskIndex = 0;\r
+    TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );\r
+    AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );\r
+    FreeLibrary( AvrtDll );\r
+  }\r
+\r
+  // start capture stream if applicable\r
+  if ( captureAudioClient ) {\r
+    hr = captureAudioClient->GetMixFormat( &captureFormat );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
+      goto Exit;\r
+    }\r
+\r
+    captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );\r
+\r
+    // initialize capture stream according to desire buffer size\r
+    float desiredBufferSize = stream_.bufferSize * captureSrRatio;\r
+    REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );\r
+\r
+    if ( !captureClient ) {\r
+      hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,\r
+                                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK,\r
+                                           desiredBufferPeriod,\r
+                                           desiredBufferPeriod,\r
+                                           captureFormat,\r
+                                           NULL );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";\r
+        goto Exit;\r
+      }\r
+\r
+      hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),\r
+                                           ( void** ) &captureClient );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";\r
+        goto Exit;\r
+      }\r
+\r
+      // configure captureEvent to trigger on every available capture buffer\r
+      captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
+      if ( !captureEvent ) {\r
+        errorType = RtAudioError::SYSTEM_ERROR;\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";\r
+        goto Exit;\r
+      }\r
+\r
+      hr = captureAudioClient->SetEventHandle( captureEvent );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";\r
+        goto Exit;\r
+      }\r
+\r
+      ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;\r
+      ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;\r
+    }\r
+\r
+    unsigned int inBufferSize = 0;\r
+    hr = captureAudioClient->GetBufferSize( &inBufferSize );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";\r
+      goto Exit;\r
+    }\r
+\r
+    // scale outBufferSize according to stream->user sample rate ratio\r
+    unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];\r
+    inBufferSize *= stream_.nDeviceChannels[INPUT];\r
+\r
+    // set captureBuffer size\r
+    captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );\r
+\r
+    // reset the capture stream\r
+    hr = captureAudioClient->Reset();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";\r
+      goto Exit;\r
+    }\r
+\r
+    // start the capture stream\r
+    hr = captureAudioClient->Start();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  // start render stream if applicable\r
+  if ( renderAudioClient ) {\r
+    hr = renderAudioClient->GetMixFormat( &renderFormat );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
+      goto Exit;\r
+    }\r
+\r
+    renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );\r
+\r
+    // initialize render stream according to desire buffer size\r
+    float desiredBufferSize = stream_.bufferSize * renderSrRatio;\r
+    REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );\r
+\r
+    if ( !renderClient ) {\r
+      hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,\r
+                                          AUDCLNT_STREAMFLAGS_EVENTCALLBACK,\r
+                                          desiredBufferPeriod,\r
+                                          desiredBufferPeriod,\r
+                                          renderFormat,\r
+                                          NULL );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";\r
+        goto Exit;\r
+      }\r
+\r
+      hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),\r
+                                          ( void** ) &renderClient );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";\r
+        goto Exit;\r
+      }\r
+\r
+      // configure renderEvent to trigger on every available render buffer\r
+      renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
+      if ( !renderEvent ) {\r
+        errorType = RtAudioError::SYSTEM_ERROR;\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";\r
+        goto Exit;\r
+      }\r
+\r
+      hr = renderAudioClient->SetEventHandle( renderEvent );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";\r
+        goto Exit;\r
+      }\r
+\r
+      ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;\r
+      ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;\r
+    }\r
+\r
+    unsigned int outBufferSize = 0;\r
+    hr = renderAudioClient->GetBufferSize( &outBufferSize );\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";\r
+      goto Exit;\r
+    }\r
+\r
+    // scale inBufferSize according to user->stream sample rate ratio\r
+    unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];\r
+    outBufferSize *= stream_.nDeviceChannels[OUTPUT];\r
+\r
+    // set renderBuffer size\r
+    renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
+\r
+    // reset the render stream\r
+    hr = renderAudioClient->Reset();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";\r
+      goto Exit;\r
+    }\r
+\r
+    // start the render stream\r
+    hr = renderAudioClient->Start();\r
+    if ( FAILED( hr ) ) {\r
+      errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT ) {\r
+    convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );\r
+    deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );\r
+  }\r
+  else if ( stream_.mode == OUTPUT ) {\r
+    convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );\r
+    deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );\r
+  }\r
+  else if ( stream_.mode == DUPLEX ) {\r
+    convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
+                             ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
+    deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
+                               stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
+  }\r
+\r
+  convBuffer = ( char* ) malloc( convBuffSize );\r
+  stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );\r
+  if ( !convBuffer || !stream_.deviceBuffer ) {\r
+    errorType = RtAudioError::MEMORY_ERROR;\r
+    errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";\r
+    goto Exit;\r
+  }\r
+\r
+  // stream process loop\r
+  while ( stream_.state != STREAM_STOPPING ) {\r
+    if ( !callbackPulled ) {\r
+      // Callback Input\r
+      // ==============\r
+      // 1. Pull callback buffer from inputBuffer\r
+      // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count\r
+      //                          Convert callback buffer to user format\r
+\r
+      if ( captureAudioClient ) {\r
+        // Pull callback buffer from inputBuffer\r
+        callbackPulled = captureBuffer.pullBuffer( convBuffer,\r
+                                                   ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],\r
+                                                   stream_.deviceFormat[INPUT] );\r
+\r
+        if ( callbackPulled ) {\r
+          // Convert callback buffer to user sample rate\r
+          convertBufferWasapi( stream_.deviceBuffer,\r
+                               convBuffer,\r
+                               stream_.nDeviceChannels[INPUT],\r
+                               captureFormat->nSamplesPerSec,\r
+                               stream_.sampleRate,\r
+                               ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),\r
+                               convBufferSize,\r
+                               stream_.deviceFormat[INPUT] );\r
+\r
+          if ( stream_.doConvertBuffer[INPUT] ) {\r
+            // Convert callback buffer to user format\r
+            convertBuffer( stream_.userBuffer[INPUT],\r
+                           stream_.deviceBuffer,\r
+                           stream_.convertInfo[INPUT] );\r
+          }\r
+          else {\r
+            // no further conversion, simple copy deviceBuffer to userBuffer\r
+            memcpy( stream_.userBuffer[INPUT],\r
+                    stream_.deviceBuffer,\r
+                    stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );\r
+          }\r
+        }\r
+      }\r
+      else {\r
+        // if there is no capture stream, set callbackPulled flag\r
+        callbackPulled = true;\r
+      }\r
+\r
+      // Execute Callback\r
+      // ================\r
+      // 1. Execute user callback method\r
+      // 2. Handle return value from callback\r
+\r
+      // if callback has not requested the stream to stop\r
+      if ( callbackPulled && !callbackStopped ) {\r
+        // Execute user callback method\r
+        callbackResult = callback( stream_.userBuffer[OUTPUT],\r
+                                   stream_.userBuffer[INPUT],\r
+                                   stream_.bufferSize,\r
+                                   getStreamTime(),\r
+                                   captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,\r
+                                   stream_.callbackInfo.userData );\r
+\r
+        // Handle return value from callback\r
+        if ( callbackResult == 1 ) {\r
+          // instantiate a thread to stop this thread\r
+          HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );\r
+          if ( !threadHandle ) {\r
+            errorType = RtAudioError::THREAD_ERROR;\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";\r
+            goto Exit;\r
+          }\r
+          else if ( !CloseHandle( threadHandle ) ) {\r
+            errorType = RtAudioError::THREAD_ERROR;\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";\r
+            goto Exit;\r
+          }\r
+\r
+          callbackStopped = true;\r
+        }\r
+        else if ( callbackResult == 2 ) {\r
+          // instantiate a thread to stop this thread\r
+          HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );\r
+          if ( !threadHandle ) {\r
+            errorType = RtAudioError::THREAD_ERROR;\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";\r
+            goto Exit;\r
+          }\r
+          else if ( !CloseHandle( threadHandle ) ) {\r
+            errorType = RtAudioError::THREAD_ERROR;\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";\r
+            goto Exit;\r
+          }\r
+\r
+          callbackStopped = true;\r
+        }\r
+      }\r
+    }\r
+\r
+    // Callback Output\r
+    // ===============\r
+    // 1. Convert callback buffer to stream format\r
+    // 2. Convert callback buffer to stream sample rate and channel count\r
+    // 3. Push callback buffer into outputBuffer\r
+\r
+    if ( renderAudioClient && callbackPulled ) {\r
+      if ( stream_.doConvertBuffer[OUTPUT] ) {\r
+        // Convert callback buffer to stream format\r
+        convertBuffer( stream_.deviceBuffer,\r
+                       stream_.userBuffer[OUTPUT],\r
+                       stream_.convertInfo[OUTPUT] );\r
+\r
+      }\r
+\r
+      // Convert callback buffer to stream sample rate\r
+      convertBufferWasapi( convBuffer,\r
+                           stream_.deviceBuffer,\r
+                           stream_.nDeviceChannels[OUTPUT],\r
+                           stream_.sampleRate,\r
+                           renderFormat->nSamplesPerSec,\r
+                           stream_.bufferSize,\r
+                           convBufferSize,\r
+                           stream_.deviceFormat[OUTPUT] );\r
+\r
+      // Push callback buffer into outputBuffer\r
+      callbackPushed = renderBuffer.pushBuffer( convBuffer,\r
+                                                convBufferSize * stream_.nDeviceChannels[OUTPUT],\r
+                                                stream_.deviceFormat[OUTPUT] );\r
+    }\r
+    else {\r
+      // if there is no render stream, set callbackPushed flag\r
+      callbackPushed = true;\r
+    }\r
+\r
+    // Stream Capture\r
+    // ==============\r
+    // 1. Get capture buffer from stream\r
+    // 2. Push capture buffer into inputBuffer\r
+    // 3. If 2. was successful: Release capture buffer\r
+\r
+    if ( captureAudioClient ) {\r
+      // if the callback input buffer was not pulled from captureBuffer, wait for next capture event\r
+      if ( !callbackPulled ) {\r
+        WaitForSingleObject( captureEvent, INFINITE );\r
+      }\r
+\r
+      // Get capture buffer from stream\r
+      hr = captureClient->GetBuffer( &streamBuffer,\r
+                                     &bufferFrameCount,\r
+                                     &captureFlags, NULL, NULL );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";\r
+        goto Exit;\r
+      }\r
+\r
+      if ( bufferFrameCount != 0 ) {\r
+        // Push capture buffer into inputBuffer\r
+        if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,\r
+                                       bufferFrameCount * stream_.nDeviceChannels[INPUT],\r
+                                       stream_.deviceFormat[INPUT] ) )\r
+        {\r
+          // Release capture buffer\r
+          hr = captureClient->ReleaseBuffer( bufferFrameCount );\r
+          if ( FAILED( hr ) ) {\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+            goto Exit;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          // Inform WASAPI that capture was unsuccessful\r
+          hr = captureClient->ReleaseBuffer( 0 );\r
+          if ( FAILED( hr ) ) {\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+            goto Exit;\r
+          }\r
+        }\r
+      }\r
+      else\r
+      {\r
+        // Inform WASAPI that capture was unsuccessful\r
+        hr = captureClient->ReleaseBuffer( 0 );\r
+        if ( FAILED( hr ) ) {\r
+          errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+          goto Exit;\r
+        }\r
+      }\r
+    }\r
+\r
+    // Stream Render\r
+    // =============\r
+    // 1. Get render buffer from stream\r
+    // 2. Pull next buffer from outputBuffer\r
+    // 3. If 2. was successful: Fill render buffer with next buffer\r
+    //                          Release render buffer\r
+\r
+    if ( renderAudioClient ) {\r
+      // if the callback output buffer was not pushed to renderBuffer, wait for next render event\r
+      if ( callbackPulled && !callbackPushed ) {\r
+        WaitForSingleObject( renderEvent, INFINITE );\r
+      }\r
+\r
+      // Get render buffer from stream\r
+      hr = renderAudioClient->GetBufferSize( &bufferFrameCount );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";\r
+        goto Exit;\r
+      }\r
+\r
+      hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );\r
+      if ( FAILED( hr ) ) {\r
+        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";\r
+        goto Exit;\r
+      }\r
+\r
+      bufferFrameCount -= numFramesPadding;\r
+\r
+      if ( bufferFrameCount != 0 ) {\r
+        hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );\r
+        if ( FAILED( hr ) ) {\r
+          errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";\r
+          goto Exit;\r
+        }\r
+\r
+        // Pull next buffer from outputBuffer\r
+        // Fill render buffer with next buffer\r
+        if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,\r
+                                      bufferFrameCount * stream_.nDeviceChannels[OUTPUT],\r
+                                      stream_.deviceFormat[OUTPUT] ) )\r
+        {\r
+          // Release render buffer\r
+          hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );\r
+          if ( FAILED( hr ) ) {\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+            goto Exit;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          // Inform WASAPI that render was unsuccessful\r
+          hr = renderClient->ReleaseBuffer( 0, 0 );\r
+          if ( FAILED( hr ) ) {\r
+            errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+            goto Exit;\r
+          }\r
+        }\r
+      }\r
+      else\r
+      {\r
+        // Inform WASAPI that render was unsuccessful\r
+        hr = renderClient->ReleaseBuffer( 0, 0 );\r
+        if ( FAILED( hr ) ) {\r
+          errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+          goto Exit;\r
+        }\r
+      }\r
+    }\r
+\r
+    // if the callback buffer was pushed renderBuffer reset callbackPulled flag\r
+    if ( callbackPushed ) {\r
+      callbackPulled = false;\r
+    }\r
+\r
+    // tick stream time\r
+    RtApi::tickStreamTime();\r
+  }\r
+\r
+Exit:\r
+  // clean up\r
+  CoTaskMemFree( captureFormat );\r
+  CoTaskMemFree( renderFormat );\r
+\r
+  free ( convBuffer );\r
+\r
+  CoUninitialize();\r
+\r
+  // update stream state\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+  if ( errorText_.empty() )\r
+    return;\r
+  else\r
+    error( errorType );\r
+}\r
+\r
+//******************** End of __WINDOWS_WASAPI__ *********************//\r
+#endif\r
+\r
+\r
+#if defined(__WINDOWS_DS__) // Windows DirectSound API\r
+\r
+// Modified by Robin Davies, October 2005\r
+// - Improvements to DirectX pointer chasing. \r
+// - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.\r
+// - Auto-call CoInitialize for DSOUND and ASIO platforms.\r
+// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007\r
+// Changed device query structure for RtAudio 4.0.7, January 2010\r
+\r
+#include <dsound.h>\r
+#include <assert.h>\r
+#include <algorithm>\r
+\r
+#if defined(__MINGW32__)\r
+  // missing from latest mingw winapi\r
+#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */\r
+#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */\r
+#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */\r
+#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */\r
+#endif\r
+\r
+#define MINIMUM_DEVICE_BUFFER_SIZE 32768\r
+\r
+#ifdef _MSC_VER // if Microsoft Visual C++\r
+#pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.\r
+#endif\r
+\r
+static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )\r
+{\r
+  if ( pointer > bufferSize ) pointer -= bufferSize;\r
+  if ( laterPointer < earlierPointer ) laterPointer += bufferSize;\r
+  if ( pointer < earlierPointer ) pointer += bufferSize;\r
+  return pointer >= earlierPointer && pointer < laterPointer;\r
+}\r
+\r
+// A structure to hold various information related to the DirectSound\r
+// API implementation.\r
+struct DsHandle {\r
+  unsigned int drainCounter; // Tracks callback counts when draining\r
+  bool internalDrain;        // Indicates if stop is initiated from callback or not.\r
+  void *id[2];\r
+  void *buffer[2];\r
+  bool xrun[2];\r
+  UINT bufferPointer[2];  \r
+  DWORD dsBufferSize[2];\r
+  DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.\r
+  HANDLE condition;\r
+\r
+  DsHandle()\r
+    :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }\r
+};\r
+\r
+// Declarations for utility functions, callbacks, and structures\r
+// specific to the DirectSound implementation.\r
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,\r
+                                          LPCTSTR description,\r
+                                          LPCTSTR module,\r
+                                          LPVOID lpContext );\r
+\r
+static const char* getErrorString( int code );\r
+\r
+static unsigned __stdcall callbackHandler( void *ptr );\r
+\r
+struct DsDevice {\r
+  LPGUID id[2];\r
+  bool validId[2];\r
+  bool found;\r
+  std::string name;\r
+\r
+  DsDevice()\r
+  : found(false) { validId[0] = false; validId[1] = false; }\r
+};\r
+\r
+struct DsProbeData {\r
+  bool isInput;\r
+  std::vector<struct DsDevice>* dsDevices;\r
+};\r
+\r
+RtApiDs :: RtApiDs()\r
+{\r
+  // Dsound will run both-threaded. If CoInitialize fails, then just\r
+  // accept whatever the mainline chose for a threading model.\r
+  coInitialized_ = false;\r
+  HRESULT hr = CoInitialize( NULL );\r
+  if ( !FAILED( hr ) ) coInitialized_ = true;\r
+}\r
+\r
+RtApiDs :: ~RtApiDs()\r
+{\r
+  if ( coInitialized_ ) CoUninitialize(); // balanced call.\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+}\r
+\r
+// The DirectSound default output is always the first device.\r
+unsigned int RtApiDs :: getDefaultOutputDevice( void )\r
+{\r
+  return 0;\r
+}\r
+\r
+// The DirectSound default input is always the first input device,\r
+// which is the first capture device enumerated.\r
+unsigned int RtApiDs :: getDefaultInputDevice( void )\r
+{\r
+  return 0;\r
+}\r
+\r
+unsigned int RtApiDs :: getDeviceCount( void )\r
+{\r
+  // Set query flag for previously found devices to false, so that we\r
+  // can check for any devices that have disappeared.\r
+  for ( unsigned int i=0; i<dsDevices.size(); i++ )\r
+    dsDevices[i].found = false;\r
+\r
+  // Query DirectSound devices.\r
+  struct DsProbeData probeInfo;\r
+  probeInfo.isInput = false;\r
+  probeInfo.dsDevices = &dsDevices;\r
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
+  if ( FAILED( result ) ) {\r
+    errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+  }\r
+\r
+  // Query DirectSoundCapture devices.\r
+  probeInfo.isInput = true;\r
+  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
+  if ( FAILED( result ) ) {\r
+    errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+  }\r
+\r
+  // Clean out any devices that may have disappeared.\r
+  std::vector< int > indices;\r
+  for ( unsigned int i=0; i<dsDevices.size(); i++ )\r
+    if ( dsDevices[i].found == false ) indices.push_back( i );\r
+  //unsigned int nErased = 0;\r
+  for ( unsigned int i=0; i<indices.size(); i++ )\r
+    dsDevices.erase( dsDevices.begin()+indices[i] );\r
+  //dsDevices.erase( dsDevices.begin()-nErased++ );\r
+\r
+  return static_cast<unsigned int>(dsDevices.size());\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  if ( dsDevices.size() == 0 ) {\r
+    // Force a query of all devices\r
+    getDeviceCount();\r
+    if ( dsDevices.size() == 0 ) {\r
+      errorText_ = "RtApiDs::getDeviceInfo: no devices found!";\r
+      error( RtAudioError::INVALID_USE );\r
+      return info;\r
+    }\r
+  }\r
+\r
+  if ( device >= dsDevices.size() ) {\r
+    errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  HRESULT result;\r
+  if ( dsDevices[ device ].validId[0] == false ) goto probeInput;\r
+\r
+  LPDIRECTSOUND output;\r
+  DSCAPS outCaps;\r
+  result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );\r
+  if ( FAILED( result ) ) {\r
+    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    goto probeInput;\r
+  }\r
+\r
+  outCaps.dwSize = sizeof( outCaps );\r
+  result = output->GetCaps( &outCaps );\r
+  if ( FAILED( result ) ) {\r
+    output->Release();\r
+    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    goto probeInput;\r
+  }\r
+\r
+  // Get output channel information.\r
+  info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;\r
+\r
+  // Get sample rate information.\r
+  info.sampleRates.clear();\r
+  for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
+    if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&\r
+         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate )\r
+      info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+  }\r
+\r
+  // Get format information.\r
+  if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;\r
+  if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;\r
+\r
+  output->Release();\r
+\r
+  if ( getDefaultOutputDevice() == device )\r
+    info.isDefaultOutput = true;\r
+\r
+  if ( dsDevices[ device ].validId[1] == false ) {\r
+    info.name = dsDevices[ device ].name;\r
+    info.probed = true;\r
+    return info;\r
+  }\r
+\r
+ probeInput:\r
+\r
+  LPDIRECTSOUNDCAPTURE input;\r
+  result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );\r
+  if ( FAILED( result ) ) {\r
+    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  DSCCAPS inCaps;\r
+  inCaps.dwSize = sizeof( inCaps );\r
+  result = input->GetCaps( &inCaps );\r
+  if ( FAILED( result ) ) {\r
+    input->Release();\r
+    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Get input channel information.\r
+  info.inputChannels = inCaps.dwChannels;\r
+\r
+  // Get sample rate and format information.\r
+  std::vector<unsigned int> rates;\r
+  if ( inCaps.dwChannels >= 2 ) {\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+\r
+    if ( info.nativeFormats & RTAUDIO_SINT16 ) {\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );\r
+    }\r
+    else if ( info.nativeFormats & RTAUDIO_SINT8 ) {\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );\r
+    }\r
+  }\r
+  else if ( inCaps.dwChannels == 1 ) {\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+    if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
+\r
+    if ( info.nativeFormats & RTAUDIO_SINT16 ) {\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );\r
+    }\r
+    else if ( info.nativeFormats & RTAUDIO_SINT8 ) {\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );\r
+      if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );\r
+    }\r
+  }\r
+  else info.inputChannels = 0; // technically, this would be an error\r
+\r
+  input->Release();\r
+\r
+  if ( info.inputChannels == 0 ) return info;\r
+\r
+  // Copy the supported rates to the info structure but avoid duplication.\r
+  bool found;\r
+  for ( unsigned int i=0; i<rates.size(); i++ ) {\r
+    found = false;\r
+    for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {\r
+      if ( rates[i] == info.sampleRates[j] ) {\r
+        found = true;\r
+        break;\r
+      }\r
+    }\r
+    if ( found == false ) info.sampleRates.push_back( rates[i] );\r
+  }\r
+  std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
+\r
+  // If device opens for both playback and capture, we determine the channels.\r
+  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
+    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+\r
+  if ( device == 0 ) info.isDefaultInput = true;\r
+\r
+  // Copy name and return.\r
+  info.name = dsDevices[ device ].name;\r
+  info.probed = true;\r
+  return info;\r
+}\r
+\r
+bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                 unsigned int firstChannel, unsigned int sampleRate,\r
+                                 RtAudioFormat format, unsigned int *bufferSize,\r
+                                 RtAudio::StreamOptions *options )\r
+{\r
+  if ( channels + firstChannel > 2 ) {\r
+    errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";\r
+    return FAILURE;\r
+  }\r
+\r
+  size_t nDevices = dsDevices.size();\r
+  if ( nDevices == 0 ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( mode == OUTPUT ) {\r
+    if ( dsDevices[ device ].validId[0] == false ) {\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+  else { // mode == INPUT\r
+    if ( dsDevices[ device ].validId[1] == false ) {\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // According to a note in PortAudio, using GetDesktopWindow()\r
+  // instead of GetForegroundWindow() is supposed to avoid problems\r
+  // that occur when the application's window is not the foreground\r
+  // window.  Also, if the application window closes before the\r
+  // DirectSound buffer, DirectSound can crash.  In the past, I had\r
+  // problems when using GetDesktopWindow() but it seems fine now\r
+  // (January 2010).  I'll leave it commented here.\r
+  // HWND hWnd = GetForegroundWindow();\r
+  HWND hWnd = GetDesktopWindow();\r
+\r
+  // Check the numberOfBuffers parameter and limit the lowest value to\r
+  // two.  This is a judgement call and a value of two is probably too\r
+  // low for capture, but it should work for playback.\r
+  int nBuffers = 0;\r
+  if ( options ) nBuffers = options->numberOfBuffers;\r
+  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;\r
+  if ( nBuffers < 2 ) nBuffers = 3;\r
+\r
+  // Check the lower range of the user-specified buffer size and set\r
+  // (arbitrarily) to a lower bound of 32.\r
+  if ( *bufferSize < 32 ) *bufferSize = 32;\r
+\r
+  // Create the wave format structure.  The data format setting will\r
+  // be determined later.\r
+  WAVEFORMATEX waveFormat;\r
+  ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );\r
+  waveFormat.wFormatTag = WAVE_FORMAT_PCM;\r
+  waveFormat.nChannels = channels + firstChannel;\r
+  waveFormat.nSamplesPerSec = (unsigned long) sampleRate;\r
+\r
+  // Determine the device buffer size. By default, we'll use the value\r
+  // defined above (32K), but we will grow it to make allowances for\r
+  // very large software buffer sizes.\r
+  DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;\r
+  DWORD dsPointerLeadTime = 0;\r
+\r
+  void *ohandle = 0, *bhandle = 0;\r
+  HRESULT result;\r
+  if ( mode == OUTPUT ) {\r
+\r
+    LPDIRECTSOUND output;\r
+    result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    DSCAPS outCaps;\r
+    outCaps.dwSize = sizeof( outCaps );\r
+    result = output->GetCaps( &outCaps );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Check channel information.\r
+    if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {\r
+      errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Check format information.  Use 16-bit format unless not\r
+    // supported or user requests 8-bit.\r
+    if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&\r
+         !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {\r
+      waveFormat.wBitsPerSample = 16;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+    }\r
+    else {\r
+      waveFormat.wBitsPerSample = 8;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+    }\r
+    stream_.userFormat = format;\r
+\r
+    // Update wave format structure and buffer information.\r
+    waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;\r
+    waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;\r
+    dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;\r
+\r
+    // If the user wants an even bigger buffer, increase the device buffer size accordingly.\r
+    while ( dsPointerLeadTime * 2U > dsBufferSize )\r
+      dsBufferSize *= 2;\r
+\r
+    // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.\r
+    // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );\r
+    // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.\r
+    result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Even though we will write to the secondary buffer, we need to\r
+    // access the primary buffer to set the correct output format\r
+    // (since the default is 8-bit, 22 kHz!).  Setup the DS primary\r
+    // buffer description.\r
+    DSBUFFERDESC bufferDescription;\r
+    ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );\r
+    bufferDescription.dwSize = sizeof( DSBUFFERDESC );\r
+    bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;\r
+\r
+    // Obtain the primary buffer\r
+    LPDIRECTSOUNDBUFFER buffer;\r
+    result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Set the primary DS buffer sound format.\r
+    result = buffer->SetFormat( &waveFormat );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Setup the secondary DS buffer description.\r
+    ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );\r
+    bufferDescription.dwSize = sizeof( DSBUFFERDESC );\r
+    bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |\r
+                                  DSBCAPS_GLOBALFOCUS |\r
+                                  DSBCAPS_GETCURRENTPOSITION2 |\r
+                                  DSBCAPS_LOCHARDWARE );  // Force hardware mixing\r
+    bufferDescription.dwBufferBytes = dsBufferSize;\r
+    bufferDescription.lpwfxFormat = &waveFormat;\r
+\r
+    // Try to create the secondary DS buffer.  If that doesn't work,\r
+    // try to use software mixing.  Otherwise, there's a problem.\r
+    result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
+    if ( FAILED( result ) ) {\r
+      bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |\r
+                                    DSBCAPS_GLOBALFOCUS |\r
+                                    DSBCAPS_GETCURRENTPOSITION2 |\r
+                                    DSBCAPS_LOCSOFTWARE );  // Force software mixing\r
+      result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
+      if ( FAILED( result ) ) {\r
+        output->Release();\r
+        errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";\r
+        errorText_ = errorStream_.str();\r
+        return FAILURE;\r
+      }\r
+    }\r
+\r
+    // Get the buffer size ... might be different from what we specified.\r
+    DSBCAPS dsbcaps;\r
+    dsbcaps.dwSize = sizeof( DSBCAPS );\r
+    result = buffer->GetCaps( &dsbcaps );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    dsBufferSize = dsbcaps.dwBufferBytes;\r
+\r
+    // Lock the DS buffer\r
+    LPVOID audioPtr;\r
+    DWORD dataLen;\r
+    result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Zero the DS buffer\r
+    ZeroMemory( audioPtr, dataLen );\r
+\r
+    // Unlock the DS buffer\r
+    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      output->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    ohandle = (void *) output;\r
+    bhandle = (void *) buffer;\r
+  }\r
+\r
+  if ( mode == INPUT ) {\r
+\r
+    LPDIRECTSOUNDCAPTURE input;\r
+    result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    DSCCAPS inCaps;\r
+    inCaps.dwSize = sizeof( inCaps );\r
+    result = input->GetCaps( &inCaps );\r
+    if ( FAILED( result ) ) {\r
+      input->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Check channel information.\r
+    if ( inCaps.dwChannels < channels + firstChannel ) {\r
+      errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";\r
+      return FAILURE;\r
+    }\r
+\r
+    // Check format information.  Use 16-bit format unless user\r
+    // requests 8-bit.\r
+    DWORD deviceFormats;\r
+    if ( channels + firstChannel == 2 ) {\r
+      deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;\r
+      if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {\r
+        waveFormat.wBitsPerSample = 8;\r
+        stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+      }\r
+      else { // assume 16-bit is supported\r
+        waveFormat.wBitsPerSample = 16;\r
+        stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+      }\r
+    }\r
+    else { // channel == 1\r
+      deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;\r
+      if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {\r
+        waveFormat.wBitsPerSample = 8;\r
+        stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+      }\r
+      else { // assume 16-bit is supported\r
+        waveFormat.wBitsPerSample = 16;\r
+        stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+      }\r
+    }\r
+    stream_.userFormat = format;\r
+\r
+    // Update wave format structure and buffer information.\r
+    waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;\r
+    waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;\r
+    dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;\r
+\r
+    // If the user wants an even bigger buffer, increase the device buffer size accordingly.\r
+    while ( dsPointerLeadTime * 2U > dsBufferSize )\r
+      dsBufferSize *= 2;\r
+\r
+    // Setup the secondary DS buffer description.\r
+    DSCBUFFERDESC bufferDescription;\r
+    ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );\r
+    bufferDescription.dwSize = sizeof( DSCBUFFERDESC );\r
+    bufferDescription.dwFlags = 0;\r
+    bufferDescription.dwReserved = 0;\r
+    bufferDescription.dwBufferBytes = dsBufferSize;\r
+    bufferDescription.lpwfxFormat = &waveFormat;\r
+\r
+    // Create the capture buffer.\r
+    LPDIRECTSOUNDCAPTUREBUFFER buffer;\r
+    result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );\r
+    if ( FAILED( result ) ) {\r
+      input->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Get the buffer size ... might be different from what we specified.\r
+    DSCBCAPS dscbcaps;\r
+    dscbcaps.dwSize = sizeof( DSCBCAPS );\r
+    result = buffer->GetCaps( &dscbcaps );\r
+    if ( FAILED( result ) ) {\r
+      input->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    dsBufferSize = dscbcaps.dwBufferBytes;\r
+\r
+    // NOTE: We could have a problem here if this is a duplex stream\r
+    // and the play and capture hardware buffer sizes are different\r
+    // (I'm actually not sure if that is a problem or not).\r
+    // Currently, we are not verifying that.\r
+\r
+    // Lock the capture buffer\r
+    LPVOID audioPtr;\r
+    DWORD dataLen;\r
+    result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      input->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    // Zero the buffer\r
+    ZeroMemory( audioPtr, dataLen );\r
+\r
+    // Unlock the buffer\r
+    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      input->Release();\r
+      buffer->Release();\r
+      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+\r
+    ohandle = (void *) input;\r
+    bhandle = (void *) buffer;\r
+  }\r
+\r
+  // Set various stream parameters\r
+  DsHandle *handle = 0;\r
+  stream_.nDeviceChannels[mode] = channels + firstChannel;\r
+  stream_.nUserChannels[mode] = channels;\r
+  stream_.bufferSize = *bufferSize;\r
+  stream_.channelOffset[mode] = firstChannel;\r
+  stream_.deviceInterleaved[mode] = true;\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
+\r
+  // Set flag for buffer conversion\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if (stream_.userFormat != stream_.deviceFormat[mode])\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+       stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate necessary internal buffers\r
+  long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  // Allocate our DsHandle structures for the stream.\r
+  if ( stream_.apiHandle == 0 ) {\r
+    try {\r
+      handle = new DsHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";\r
+      goto error;\r
+    }\r
+\r
+    // Create a manual-reset event.\r
+    handle->condition = CreateEvent( NULL,   // no security\r
+                                     TRUE,   // manual-reset\r
+                                     FALSE,  // non-signaled initially\r
+                                     NULL ); // unnamed\r
+    stream_.apiHandle = (void *) handle;\r
+  }\r
+  else\r
+    handle = (DsHandle *) stream_.apiHandle;\r
+  handle->id[mode] = ohandle;\r
+  handle->buffer[mode] = bhandle;\r
+  handle->dsBufferSize[mode] = dsBufferSize;\r
+  handle->dsPointerLeadTime[mode] = dsPointerLeadTime;\r
+\r
+  stream_.device[mode] = device;\r
+  stream_.state = STREAM_STOPPED;\r
+  if ( stream_.mode == OUTPUT && mode == INPUT )\r
+    // We had already set up an output stream.\r
+    stream_.mode = DUPLEX;\r
+  else\r
+    stream_.mode = mode;\r
+  stream_.nBuffers = nBuffers;\r
+  stream_.sampleRate = sampleRate;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
+  // Setup the callback thread.\r
+  if ( stream_.callbackInfo.isRunning == false ) {\r
+    unsigned threadId;\r
+    stream_.callbackInfo.isRunning = true;\r
+    stream_.callbackInfo.object = (void *) this;\r
+    stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,\r
+                                                  &stream_.callbackInfo, 0, &threadId );\r
+    if ( stream_.callbackInfo.thread == 0 ) {\r
+      errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";\r
+      goto error;\r
+    }\r
+\r
+    // Boost DS thread priority\r
+    SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );\r
+  }\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( handle ) {\r
+    if ( handle->buffer[0] ) { // the object pointer can be NULL and valid\r
+      LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];\r
+      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+      if ( buffer ) buffer->Release();\r
+      object->Release();\r
+    }\r
+    if ( handle->buffer[1] ) {\r
+      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];\r
+      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+      if ( buffer ) buffer->Release();\r
+      object->Release();\r
+    }\r
+    CloseHandle( handle->condition );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.state = STREAM_CLOSED;\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiDs :: closeStream()\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiDs::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // Stop the callback thread.\r
+  stream_.callbackInfo.isRunning = false;\r
+  WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );\r
+  CloseHandle( (HANDLE) stream_.callbackInfo.thread );\r
+\r
+  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
+  if ( handle ) {\r
+    if ( handle->buffer[0] ) { // the object pointer can be NULL and valid\r
+      LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];\r
+      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+      if ( buffer ) {\r
+        buffer->Stop();\r
+        buffer->Release();\r
+      }\r
+      object->Release();\r
+    }\r
+    if ( handle->buffer[1] ) {\r
+      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];\r
+      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+      if ( buffer ) {\r
+        buffer->Stop();\r
+        buffer->Release();\r
+      }\r
+      object->Release();\r
+    }\r
+    CloseHandle( handle->condition );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+void RtApiDs :: startStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiDs::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
+\r
+  // Increase scheduler frequency on lesser windows (a side-effect of\r
+  // increasing timer accuracy).  On greater windows (Win2K or later),\r
+  // this is already in effect.\r
+  timeBeginPeriod( 1 ); \r
+\r
+  buffersRolling = false;\r
+  duplexPrerollBytes = 0;\r
+\r
+  if ( stream_.mode == DUPLEX ) {\r
+    // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.\r
+    duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );\r
+  }\r
+\r
+  HRESULT result = 0;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+    result = buffer->Play( 0, 0, DSBPLAY_LOOPING );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+    result = buffer->Start( DSCBSTART_LOOPING );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  handle->drainCounter = 0;\r
+  handle->internalDrain = false;\r
+  ResetEvent( handle->condition );\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+ unlock:\r
+  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiDs :: stopStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  HRESULT result = 0;\r
+  LPVOID audioPtr;\r
+  DWORD dataLen;\r
+  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( handle->drainCounter == 0 ) {\r
+      handle->drainCounter = 2;\r
+      WaitForSingleObject( handle->condition, INFINITE );  // block until signaled\r
+    }\r
+\r
+    stream_.state = STREAM_STOPPED;\r
+\r
+    MUTEX_LOCK( &stream_.mutex );\r
+\r
+    // Stop the buffer and clear memory\r
+    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+    result = buffer->Stop();\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // Lock the buffer and clear it so that if we start to play again,\r
+    // we won't have old data playing.\r
+    result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // Zero the DS buffer\r
+    ZeroMemory( audioPtr, dataLen );\r
+\r
+    // Unlock the DS buffer\r
+    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // If we start playing again, we must begin at beginning of buffer.\r
+    handle->bufferPointer[0] = 0;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+    audioPtr = NULL;\r
+    dataLen = 0;\r
+\r
+    stream_.state = STREAM_STOPPED;\r
+\r
+    if ( stream_.mode != DUPLEX )\r
+      MUTEX_LOCK( &stream_.mutex );\r
+\r
+    result = buffer->Stop();\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // Lock the buffer and clear it so that if we start to play again,\r
+    // we won't have old data playing.\r
+    result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // Zero the DS buffer\r
+    ZeroMemory( audioPtr, dataLen );\r
+\r
+    // Unlock the DS buffer\r
+    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+\r
+    // If we start recording again, we must begin at beginning of buffer.\r
+    handle->bufferPointer[1] = 0;\r
+  }\r
+\r
+ unlock:\r
+  timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiDs :: abortStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
+  handle->drainCounter = 2;\r
+\r
+  stopStream();\r
+}\r
+\r
+void RtApiDs :: callbackEvent()\r
+{\r
+  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {\r
+    Sleep( 50 ); // sleep 50 milliseconds\r
+    return;\r
+  }\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
+  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
+\r
+  // Check if we were draining the stream and signal is finished.\r
+  if ( handle->drainCounter > stream_.nBuffers + 2 ) {\r
+\r
+    stream_.state = STREAM_STOPPING;\r
+    if ( handle->internalDrain == false )\r
+      SetEvent( handle->condition );\r
+    else\r
+      stopStream();\r
+    return;\r
+  }\r
+\r
+  // Invoke user callback to get fresh output data UNLESS we are\r
+  // draining stream.\r
+  if ( handle->drainCounter == 0 ) {\r
+    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
+    double streamTime = getStreamTime();\r
+    RtAudioStreamStatus status = 0;\r
+    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
+      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+      handle->xrun[0] = false;\r
+    }\r
+    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
+      status |= RTAUDIO_INPUT_OVERFLOW;\r
+      handle->xrun[1] = false;\r
+    }\r
+    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                                  stream_.bufferSize, streamTime, status, info->userData );\r
+    if ( cbReturnValue == 2 ) {\r
+      stream_.state = STREAM_STOPPING;\r
+      handle->drainCounter = 2;\r
+      abortStream();\r
+      return;\r
+    }\r
+    else if ( cbReturnValue == 1 ) {\r
+      handle->drainCounter = 1;\r
+      handle->internalDrain = true;\r
+    }\r
+  }\r
+\r
+  HRESULT result;\r
+  DWORD currentWritePointer, safeWritePointer;\r
+  DWORD currentReadPointer, safeReadPointer;\r
+  UINT nextWritePointer;\r
+\r
+  LPVOID buffer1 = NULL;\r
+  LPVOID buffer2 = NULL;\r
+  DWORD bufferSize1 = 0;\r
+  DWORD bufferSize2 = 0;\r
+\r
+  char *buffer;\r
+  long bufferBytes;\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+    return;\r
+  }\r
+\r
+  if ( buffersRolling == false ) {\r
+    if ( stream_.mode == DUPLEX ) {\r
+      //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );\r
+\r
+      // It takes a while for the devices to get rolling. As a result,\r
+      // there's no guarantee that the capture and write device pointers\r
+      // will move in lockstep.  Wait here for both devices to start\r
+      // rolling, and then set our buffer pointers accordingly.\r
+      // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600\r
+      // bytes later than the write buffer.\r
+\r
+      // Stub: a serious risk of having a pre-emptive scheduling round\r
+      // take place between the two GetCurrentPosition calls... but I'm\r
+      // really not sure how to solve the problem.  Temporarily boost to\r
+      // Realtime priority, maybe; but I'm not sure what priority the\r
+      // DirectSound service threads run at. We *should* be roughly\r
+      // within a ms or so of correct.\r
+\r
+      LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+      LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+\r
+      DWORD startSafeWritePointer, startSafeReadPointer;\r
+\r
+      result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );\r
+      if ( FAILED( result ) ) {\r
+        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
+      }\r
+      result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );\r
+      if ( FAILED( result ) ) {\r
+        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
+      }\r
+      while ( true ) {\r
+        result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );\r
+        if ( FAILED( result ) ) {\r
+          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
+          errorText_ = errorStream_.str();\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
+        }\r
+        result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );\r
+        if ( FAILED( result ) ) {\r
+          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
+          errorText_ = errorStream_.str();\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
+        }\r
+        if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;\r
+        Sleep( 1 );\r
+      }\r
+\r
+      //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );\r
+\r
+      handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
+      if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
+      handle->bufferPointer[1] = safeReadPointer;\r
+    }\r
+    else if ( stream_.mode == OUTPUT ) {\r
+\r
+      // Set the proper nextWritePosition after initial startup.\r
+      LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+      result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );\r
+      if ( FAILED( result ) ) {\r
+        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
+      }\r
+      handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
+      if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
+    }\r
+\r
+    buffersRolling = true;\r
+  }\r
+\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    \r
+    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
+\r
+    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
+      bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];\r
+      bufferBytes *= formatBytes( stream_.userFormat );\r
+      memset( stream_.userBuffer[0], 0, bufferBytes );\r
+    }\r
+\r
+    // Setup parameters and do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[0] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+      bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];\r
+      bufferBytes *= formatBytes( stream_.deviceFormat[0] );\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[0];\r
+      bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];\r
+      bufferBytes *= formatBytes( stream_.userFormat );\r
+    }\r
+\r
+    // No byte swapping necessary in DirectSound implementation.\r
+\r
+    // Ahhh ... windoze.  16-bit data is signed but 8-bit data is\r
+    // unsigned.  So, we need to convert our signed 8-bit data here to\r
+    // unsigned.\r
+    if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )\r
+      for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );\r
+\r
+    DWORD dsBufferSize = handle->dsBufferSize[0];\r
+    nextWritePointer = handle->bufferPointer[0];\r
+\r
+    DWORD endWrite, leadPointer;\r
+    while ( true ) {\r
+      // Find out where the read and "safe write" pointers are.\r
+      result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );\r
+      if ( FAILED( result ) ) {\r
+        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
+      }\r
+\r
+      // We will copy our output buffer into the region between\r
+      // safeWritePointer and leadPointer.  If leadPointer is not\r
+      // beyond the next endWrite position, wait until it is.\r
+      leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];\r
+      //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;\r
+      if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;\r
+      if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset\r
+      endWrite = nextWritePointer + bufferBytes;\r
+\r
+      // Check whether the entire write region is behind the play pointer.\r
+      if ( leadPointer >= endWrite ) break;\r
+\r
+      // If we are here, then we must wait until the leadPointer advances\r
+      // beyond the end of our next write region. We use the\r
+      // Sleep() function to suspend operation until that happens.\r
+      double millis = ( endWrite - leadPointer ) * 1000.0;\r
+      millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);\r
+      if ( millis < 1.0 ) millis = 1.0;\r
+      Sleep( (DWORD) millis );\r
+    }\r
+\r
+    if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )\r
+         || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { \r
+      // We've strayed into the forbidden zone ... resync the read pointer.\r
+      handle->xrun[0] = true;\r
+      nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;\r
+      if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;\r
+      handle->bufferPointer[0] = nextWritePointer;\r
+      endWrite = nextWritePointer + bufferBytes;\r
+    }\r
+\r
+    // Lock free space in the buffer\r
+    result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,\r
+                             &bufferSize1, &buffer2, &bufferSize2, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+\r
+    // Copy our buffer into the DS buffer\r
+    CopyMemory( buffer1, buffer, bufferSize1 );\r
+    if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );\r
+\r
+    // Update our buffer offset and unlock sound buffer\r
+    dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+    nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
+    handle->bufferPointer[0] = nextWritePointer;\r
+  }\r
+\r
+  // Don't bother draining input\r
+  if ( handle->drainCounter ) {\r
+    handle->drainCounter++;\r
+    goto unlock;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Setup parameters.\r
+    if ( stream_.doConvertBuffer[1] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];\r
+      bufferBytes *= formatBytes( stream_.deviceFormat[1] );\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[1];\r
+      bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];\r
+      bufferBytes *= formatBytes( stream_.userFormat );\r
+    }\r
+\r
+    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
+    long nextReadPointer = handle->bufferPointer[1];\r
+    DWORD dsBufferSize = handle->dsBufferSize[1];\r
+\r
+    // Find out where the write and "safe read" pointers are.\r
+    result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+\r
+    if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
+    DWORD endRead = nextReadPointer + bufferBytes;\r
+\r
+    // Handling depends on whether we are INPUT or DUPLEX. \r
+    // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,\r
+    // then a wait here will drag the write pointers into the forbidden zone.\r
+    // \r
+    // In DUPLEX mode, rather than wait, we will back off the read pointer until \r
+    // it's in a safe position. This causes dropouts, but it seems to be the only \r
+    // practical way to sync up the read and write pointers reliably, given the \r
+    // the very complex relationship between phase and increment of the read and write \r
+    // pointers.\r
+    //\r
+    // In order to minimize audible dropouts in DUPLEX mode, we will\r
+    // provide a pre-roll period of 0.5 seconds in which we return\r
+    // zeros from the read buffer while the pointers sync up.\r
+\r
+    if ( stream_.mode == DUPLEX ) {\r
+      if ( safeReadPointer < endRead ) {\r
+        if ( duplexPrerollBytes <= 0 ) {\r
+          // Pre-roll time over. Be more agressive.\r
+          int adjustment = endRead-safeReadPointer;\r
+\r
+          handle->xrun[1] = true;\r
+          // Two cases:\r
+          //   - large adjustments: we've probably run out of CPU cycles, so just resync exactly,\r
+          //     and perform fine adjustments later.\r
+          //   - small adjustments: back off by twice as much.\r
+          if ( adjustment >= 2*bufferBytes )\r
+            nextReadPointer = safeReadPointer-2*bufferBytes;\r
+          else\r
+            nextReadPointer = safeReadPointer-bufferBytes-adjustment;\r
+\r
+          if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;\r
+\r
+        }\r
+        else {\r
+          // In pre=roll time. Just do it.\r
+          nextReadPointer = safeReadPointer - bufferBytes;\r
+          while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;\r
+        }\r
+        endRead = nextReadPointer + bufferBytes;\r
+      }\r
+    }\r
+    else { // mode == INPUT\r
+      while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {\r
+        // See comments for playback.\r
+        double millis = (endRead - safeReadPointer) * 1000.0;\r
+        millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);\r
+        if ( millis < 1.0 ) millis = 1.0;\r
+        Sleep( (DWORD) millis );\r
+\r
+        // Wake up and find out where we are now.\r
+        result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );\r
+        if ( FAILED( result ) ) {\r
+          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
+          errorText_ = errorStream_.str();\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
+        }\r
+      \r
+        if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
+      }\r
+    }\r
+\r
+    // Lock free space in the buffer\r
+    result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,\r
+                             &bufferSize1, &buffer2, &bufferSize2, 0 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+\r
+    if ( duplexPrerollBytes <= 0 ) {\r
+      // Copy our buffer into the DS buffer\r
+      CopyMemory( buffer, buffer1, bufferSize1 );\r
+      if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );\r
+    }\r
+    else {\r
+      memset( buffer, 0, bufferSize1 );\r
+      if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );\r
+      duplexPrerollBytes -= bufferSize1 + bufferSize2;\r
+    }\r
+\r
+    // Update our buffer offset and unlock sound buffer\r
+    nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
+    dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );\r
+    if ( FAILED( result ) ) {\r
+      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+    handle->bufferPointer[1] = nextReadPointer;\r
+\r
+    // No byte swapping necessary in DirectSound implementation.\r
+\r
+    // If necessary, convert 8-bit data from unsigned to signed.\r
+    if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )\r
+      for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );\r
+\r
+    // Do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[1] )\r
+      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
+  }\r
+\r
+ unlock:\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+  RtApi::tickStreamTime();\r
+}\r
+\r
+// Definitions for utility functions and callbacks\r
+// specific to the DirectSound implementation.\r
+\r
+static unsigned __stdcall callbackHandler( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiDs *object = (RtApiDs *) info->object;\r
+  bool* isRunning = &info->isRunning;\r
+\r
+  while ( *isRunning == true ) {\r
+    object->callbackEvent();\r
+  }\r
+\r
+  _endthreadex( 0 );\r
+  return 0;\r
+}\r
+\r
+#include "tchar.h"\r
+\r
+static std::string convertTChar( LPCTSTR name )\r
+{\r
+#if defined( UNICODE ) || defined( _UNICODE )\r
+  int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);\r
+  std::string s( length-1, '\0' );\r
+  WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);\r
+#else\r
+  std::string s( name );\r
+#endif\r
+\r
+  return s;\r
+}\r
+\r
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,\r
+                                          LPCTSTR description,\r
+                                          LPCTSTR /*module*/,\r
+                                          LPVOID lpContext )\r
+{\r
+  struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;\r
+  std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;\r
+\r
+  HRESULT hr;\r
+  bool validDevice = false;\r
+  if ( probeInfo.isInput == true ) {\r
+    DSCCAPS caps;\r
+    LPDIRECTSOUNDCAPTURE object;\r
+\r
+    hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );\r
+    if ( hr != DS_OK ) return TRUE;\r
+\r
+    caps.dwSize = sizeof(caps);\r
+    hr = object->GetCaps( &caps );\r
+    if ( hr == DS_OK ) {\r
+      if ( caps.dwChannels > 0 && caps.dwFormats > 0 )\r
+        validDevice = true;\r
+    }\r
+    object->Release();\r
+  }\r
+  else {\r
+    DSCAPS caps;\r
+    LPDIRECTSOUND object;\r
+    hr = DirectSoundCreate(  lpguid, &object,   NULL );\r
+    if ( hr != DS_OK ) return TRUE;\r
+\r
+    caps.dwSize = sizeof(caps);\r
+    hr = object->GetCaps( &caps );\r
+    if ( hr == DS_OK ) {\r
+      if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )\r
+        validDevice = true;\r
+    }\r
+    object->Release();\r
+  }\r
+\r
+  // If good device, then save its name and guid.\r
+  std::string name = convertTChar( description );\r
+  //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
+  if ( lpguid == NULL )\r
+    name = "Default Device";\r
+  if ( validDevice ) {\r
+    for ( unsigned int i=0; i<dsDevices.size(); i++ ) {\r
+      if ( dsDevices[i].name == name ) {\r
+        dsDevices[i].found = true;\r
+        if ( probeInfo.isInput ) {\r
+          dsDevices[i].id[1] = lpguid;\r
+          dsDevices[i].validId[1] = true;\r
+        }\r
+        else {\r
+          dsDevices[i].id[0] = lpguid;\r
+          dsDevices[i].validId[0] = true;\r
+        }\r
+        return TRUE;\r
+      }\r
+    }\r
+\r
+    DsDevice device;\r
+    device.name = name;\r
+    device.found = true;\r
+    if ( probeInfo.isInput ) {\r
+      device.id[1] = lpguid;\r
+      device.validId[1] = true;\r
+    }\r
+    else {\r
+      device.id[0] = lpguid;\r
+      device.validId[0] = true;\r
+    }\r
+    dsDevices.push_back( device );\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+static const char* getErrorString( int code )\r
+{\r
+  switch ( code ) {\r
+\r
+  case DSERR_ALLOCATED:\r
+    return "Already allocated";\r
+\r
+  case DSERR_CONTROLUNAVAIL:\r
+    return "Control unavailable";\r
+\r
+  case DSERR_INVALIDPARAM:\r
+    return "Invalid parameter";\r
+\r
+  case DSERR_INVALIDCALL:\r
+    return "Invalid call";\r
+\r
+  case DSERR_GENERIC:\r
+    return "Generic error";\r
+\r
+  case DSERR_PRIOLEVELNEEDED:\r
+    return "Priority level needed";\r
+\r
+  case DSERR_OUTOFMEMORY:\r
+    return "Out of memory";\r
+\r
+  case DSERR_BADFORMAT:\r
+    return "The sample rate or the channel format is not supported";\r
+\r
+  case DSERR_UNSUPPORTED:\r
+    return "Not supported";\r
+\r
+  case DSERR_NODRIVER:\r
+    return "No driver";\r
+\r
+  case DSERR_ALREADYINITIALIZED:\r
+    return "Already initialized";\r
+\r
+  case DSERR_NOAGGREGATION:\r
+    return "No aggregation";\r
+\r
+  case DSERR_BUFFERLOST:\r
+    return "Buffer lost";\r
+\r
+  case DSERR_OTHERAPPHASPRIO:\r
+    return "Another application already has priority";\r
+\r
+  case DSERR_UNINITIALIZED:\r
+    return "Uninitialized";\r
+\r
+  default:\r
+    return "DirectSound unknown error";\r
+  }\r
+}\r
+//******************** End of __WINDOWS_DS__ *********************//\r
+#endif\r
+\r
+\r
+#if defined(__LINUX_ALSA__)\r
+\r
+#include <alsa/asoundlib.h>\r
+#include <unistd.h>\r
+\r
+  // A structure to hold various information related to the ALSA API\r
+  // implementation.\r
+struct AlsaHandle {\r
+  snd_pcm_t *handles[2];\r
+  bool synchronized;\r
+  bool xrun[2];\r
+  pthread_cond_t runnable_cv;\r
+  bool runnable;\r
+\r
+  AlsaHandle()\r
+    :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }\r
+};\r
+\r
+static void *alsaCallbackHandler( void * ptr );\r
+\r
+RtApiAlsa :: RtApiAlsa()\r
+{\r
+  // Nothing to do here.\r
+}\r
+\r
+RtApiAlsa :: ~RtApiAlsa()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+}\r
+\r
+unsigned int RtApiAlsa :: getDeviceCount( void )\r
+{\r
+  unsigned nDevices = 0;\r
+  int result, subdevice, card;\r
+  char name[64];\r
+  snd_ctl_t *handle;\r
+\r
+  // Count cards and devices\r
+  card = -1;\r
+  snd_card_next( &card );\r
+  while ( card >= 0 ) {\r
+    sprintf( name, "hw:%d", card );\r
+    result = snd_ctl_open( &handle, name, 0 );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::WARNING );\r
+      goto nextcard;\r
+    }\r
+    subdevice = -1;\r
+    while( 1 ) {\r
+      result = snd_ctl_pcm_next_device( handle, &subdevice );\r
+      if ( result < 0 ) {\r
+        errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::WARNING );\r
+        break;\r
+      }\r
+      if ( subdevice < 0 )\r
+        break;\r
+      nDevices++;\r
+    }\r
+  nextcard:\r
+    snd_ctl_close( handle );\r
+    snd_card_next( &card );\r
+  }\r
+\r
+  result = snd_ctl_open( &handle, "default", 0 );\r
+  if (result == 0) {\r
+    nDevices++;\r
+    snd_ctl_close( handle );\r
+  }\r
+\r
+  return nDevices;\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  unsigned nDevices = 0;\r
+  int result, subdevice, card;\r
+  char name[64];\r
+  snd_ctl_t *chandle;\r
+\r
+  // Count cards and devices\r
+  card = -1;\r
+  snd_card_next( &card );\r
+  while ( card >= 0 ) {\r
+    sprintf( name, "hw:%d", card );\r
+    result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::WARNING );\r
+      goto nextcard;\r
+    }\r
+    subdevice = -1;\r
+    while( 1 ) {\r
+      result = snd_ctl_pcm_next_device( chandle, &subdevice );\r
+      if ( result < 0 ) {\r
+        errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+        error( RtAudioError::WARNING );\r
+        break;\r
+      }\r
+      if ( subdevice < 0 ) break;\r
+      if ( nDevices == device ) {\r
+        sprintf( name, "hw:%d,%d", card, subdevice );\r
+        goto foundDevice;\r
+      }\r
+      nDevices++;\r
+    }\r
+  nextcard:\r
+    snd_ctl_close( chandle );\r
+    snd_card_next( &card );\r
+  }\r
+\r
+  result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+  if ( result == 0 ) {\r
+    if ( nDevices == device ) {\r
+      strcpy( name, "default" );\r
+      goto foundDevice;\r
+    }\r
+    nDevices++;\r
+  }\r
+\r
+  if ( nDevices == 0 ) {\r
+    errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+ foundDevice:\r
+\r
+  // If a stream is already open, we cannot probe the stream devices.\r
+  // Thus, use the saved results.\r
+  if ( stream_.state != STREAM_CLOSED &&\r
+       ( stream_.device[0] == device || stream_.device[1] == device ) ) {\r
+    snd_ctl_close( chandle );\r
+    if ( device >= devices_.size() ) {\r
+      errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";\r
+      error( RtAudioError::WARNING );\r
+      return info;\r
+    }\r
+    return devices_[ device ];\r
+  }\r
+\r
+  int openMode = SND_PCM_ASYNC;\r
+  snd_pcm_stream_t stream;\r
+  snd_pcm_info_t *pcminfo;\r
+  snd_pcm_info_alloca( &pcminfo );\r
+  snd_pcm_t *phandle;\r
+  snd_pcm_hw_params_t *params;\r
+  snd_pcm_hw_params_alloca( &params );\r
+\r
+  // First try for playback unless default device (which has subdev -1)\r
+  stream = SND_PCM_STREAM_PLAYBACK;\r
+  snd_pcm_info_set_stream( pcminfo, stream );\r
+  if ( subdevice != -1 ) {\r
+    snd_pcm_info_set_device( pcminfo, subdevice );\r
+    snd_pcm_info_set_subdevice( pcminfo, 0 );\r
+\r
+    result = snd_ctl_pcm_info( chandle, pcminfo );\r
+    if ( result < 0 ) {\r
+      // Device probably doesn't support playback.\r
+      goto captureProbe;\r
+    }\r
+  }\r
+\r
+  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );\r
+  if ( result < 0 ) {\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    goto captureProbe;\r
+  }\r
+\r
+  // The device is open ... fill the parameter structure.\r
+  result = snd_pcm_hw_params_any( phandle, params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    goto captureProbe;\r
+  }\r
+\r
+  // Get output channel information.\r
+  unsigned int value;\r
+  result = snd_pcm_hw_params_get_channels_max( params, &value );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    goto captureProbe;\r
+  }\r
+  info.outputChannels = value;\r
+  snd_pcm_close( phandle );\r
+\r
+ captureProbe:\r
+  stream = SND_PCM_STREAM_CAPTURE;\r
+  snd_pcm_info_set_stream( pcminfo, stream );\r
+\r
+  // Now try for capture unless default device (with subdev = -1)\r
+  if ( subdevice != -1 ) {\r
+    result = snd_ctl_pcm_info( chandle, pcminfo );\r
+    snd_ctl_close( chandle );\r
+    if ( result < 0 ) {\r
+      // Device probably doesn't support capture.\r
+      if ( info.outputChannels == 0 ) return info;\r
+      goto probeParameters;\r
+    }\r
+  }\r
+  else\r
+    snd_ctl_close( chandle );\r
+\r
+  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
+  if ( result < 0 ) {\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    if ( info.outputChannels == 0 ) return info;\r
+    goto probeParameters;\r
+  }\r
+\r
+  // The device is open ... fill the parameter structure.\r
+  result = snd_pcm_hw_params_any( phandle, params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    if ( info.outputChannels == 0 ) return info;\r
+    goto probeParameters;\r
+  }\r
+\r
+  result = snd_pcm_hw_params_get_channels_max( params, &value );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    if ( info.outputChannels == 0 ) return info;\r
+    goto probeParameters;\r
+  }\r
+  info.inputChannels = value;\r
+  snd_pcm_close( phandle );\r
+\r
+  // If device opens for both playback and capture, we determine the channels.\r
+  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
+    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+\r
+  // ALSA doesn't provide default devices so we'll use the first available one.\r
+  if ( device == 0 && info.outputChannels > 0 )\r
+    info.isDefaultOutput = true;\r
+  if ( device == 0 && info.inputChannels > 0 )\r
+    info.isDefaultInput = true;\r
+\r
+ probeParameters:\r
+  // At this point, we just need to figure out the supported data\r
+  // formats and sample rates.  We'll proceed by opening the device in\r
+  // the direction with the maximum number of channels, or playback if\r
+  // they are equal.  This might limit our sample rate options, but so\r
+  // be it.\r
+\r
+  if ( info.outputChannels >= info.inputChannels )\r
+    stream = SND_PCM_STREAM_PLAYBACK;\r
+  else\r
+    stream = SND_PCM_STREAM_CAPTURE;\r
+  snd_pcm_info_set_stream( pcminfo, stream );\r
+\r
+  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
+  if ( result < 0 ) {\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // The device is open ... fill the parameter structure.\r
+  result = snd_pcm_hw_params_any( phandle, params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Test our discrete set of sample rate values.\r
+  info.sampleRates.clear();\r
+  for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
+    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 )\r
+      info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+  }\r
+  if ( info.sampleRates.size() == 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Probe the supported data formats ... we don't care about endian-ness just yet\r
+  snd_pcm_format_t format;\r
+  info.nativeFormats = 0;\r
+  format = SND_PCM_FORMAT_S8;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_SINT8;\r
+  format = SND_PCM_FORMAT_S16;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_SINT16;\r
+  format = SND_PCM_FORMAT_S24;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_SINT24;\r
+  format = SND_PCM_FORMAT_S32;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_SINT32;\r
+  format = SND_PCM_FORMAT_FLOAT;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_FLOAT32;\r
+  format = SND_PCM_FORMAT_FLOAT64;\r
+  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
+    info.nativeFormats |= RTAUDIO_FLOAT64;\r
+\r
+  // Check that we have at least one supported format\r
+  if ( info.nativeFormats == 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Get the device name\r
+  char *cardname;\r
+  result = snd_card_get_name( card, &cardname );\r
+  if ( result >= 0 ) {\r
+    sprintf( name, "hw:%s,%d", cardname, subdevice );\r
+    free( cardname );\r
+  }\r
+  info.name = name;\r
+\r
+  // That's all ... close the device and return\r
+  snd_pcm_close( phandle );\r
+  info.probed = true;\r
+  return info;\r
+}\r
+\r
+void RtApiAlsa :: saveDeviceInfo( void )\r
+{\r
+  devices_.clear();\r
+\r
+  unsigned int nDevices = getDeviceCount();\r
+  devices_.resize( nDevices );\r
+  for ( unsigned int i=0; i<nDevices; i++ )\r
+    devices_[i] = getDeviceInfo( i );\r
+}\r
+\r
+bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                   unsigned int firstChannel, unsigned int sampleRate,\r
+                                   RtAudioFormat format, unsigned int *bufferSize,\r
+                                   RtAudio::StreamOptions *options )\r
+\r
+{\r
+#if defined(__RTAUDIO_DEBUG__)\r
+  snd_output_t *out;\r
+  snd_output_stdio_attach(&out, stderr, 0);\r
+#endif\r
+\r
+  // I'm not using the "plug" interface ... too much inconsistent behavior.\r
+\r
+  unsigned nDevices = 0;\r
+  int result, subdevice, card;\r
+  char name[64];\r
+  snd_ctl_t *chandle;\r
+\r
+  if ( options && options->flags & RTAUDIO_ALSA_USE_DEFAULT )\r
+    snprintf(name, sizeof(name), "%s", "default");\r
+  else {\r
+    // Count cards and devices\r
+    card = -1;\r
+    snd_card_next( &card );\r
+    while ( card >= 0 ) {\r
+      sprintf( name, "hw:%d", card );\r
+      result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );\r
+      if ( result < 0 ) {\r
+        errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+        return FAILURE;\r
+      }\r
+      subdevice = -1;\r
+      while( 1 ) {\r
+        result = snd_ctl_pcm_next_device( chandle, &subdevice );\r
+        if ( result < 0 ) break;\r
+        if ( subdevice < 0 ) break;\r
+        if ( nDevices == device ) {\r
+          sprintf( name, "hw:%d,%d", card, subdevice );\r
+          snd_ctl_close( chandle );\r
+          goto foundDevice;\r
+        }\r
+        nDevices++;\r
+      }\r
+      snd_ctl_close( chandle );\r
+      snd_card_next( &card );\r
+    }\r
+\r
+    result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+    if ( result == 0 ) {\r
+      if ( nDevices == device ) {\r
+        strcpy( name, "default" );\r
+        goto foundDevice;\r
+      }\r
+      nDevices++;\r
+    }\r
+\r
+    if ( nDevices == 0 ) {\r
+      // This should not happen because a check is made before this function is called.\r
+      errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";\r
+      return FAILURE;\r
+    }\r
+\r
+    if ( device >= nDevices ) {\r
+      // This should not happen because a check is made before this function is called.\r
+      errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!";\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+ foundDevice:\r
+\r
+  // The getDeviceInfo() function will not work for a device that is\r
+  // already open.  Thus, we'll probe the system before opening a\r
+  // stream and save the results for use by getDeviceInfo().\r
+  if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once\r
+    this->saveDeviceInfo();\r
+\r
+  snd_pcm_stream_t stream;\r
+  if ( mode == OUTPUT )\r
+    stream = SND_PCM_STREAM_PLAYBACK;\r
+  else\r
+    stream = SND_PCM_STREAM_CAPTURE;\r
+\r
+  snd_pcm_t *phandle;\r
+  int openMode = SND_PCM_ASYNC;\r
+  result = snd_pcm_open( &phandle, name, stream, openMode );\r
+  if ( result < 0 ) {\r
+    if ( mode == OUTPUT )\r
+      errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";\r
+    else\r
+      errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Fill the parameter structure.\r
+  snd_pcm_hw_params_t *hw_params;\r
+  snd_pcm_hw_params_alloca( &hw_params );\r
+  result = snd_pcm_hw_params_any( phandle, hw_params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+#if defined(__RTAUDIO_DEBUG__)\r
+  fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" );\r
+  snd_pcm_hw_params_dump( hw_params, out );\r
+#endif\r
+\r
+  // Set access ... check user preference.\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) {\r
+    stream_.userInterleaved = false;\r
+    result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );\r
+    if ( result < 0 ) {\r
+      result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );\r
+      stream_.deviceInterleaved[mode] =  true;\r
+    }\r
+    else\r
+      stream_.deviceInterleaved[mode] = false;\r
+  }\r
+  else {\r
+    stream_.userInterleaved = true;\r
+    result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );\r
+    if ( result < 0 ) {\r
+      result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );\r
+      stream_.deviceInterleaved[mode] =  false;\r
+    }\r
+    else\r
+      stream_.deviceInterleaved[mode] =  true;\r
+  }\r
+\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Determine how to set the device format.\r
+  stream_.userFormat = format;\r
+  snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN;\r
+\r
+  if ( format == RTAUDIO_SINT8 )\r
+    deviceFormat = SND_PCM_FORMAT_S8;\r
+  else if ( format == RTAUDIO_SINT16 )\r
+    deviceFormat = SND_PCM_FORMAT_S16;\r
+  else if ( format == RTAUDIO_SINT24 )\r
+    deviceFormat = SND_PCM_FORMAT_S24;\r
+  else if ( format == RTAUDIO_SINT32 )\r
+    deviceFormat = SND_PCM_FORMAT_S32;\r
+  else if ( format == RTAUDIO_FLOAT32 )\r
+    deviceFormat = SND_PCM_FORMAT_FLOAT;\r
+  else if ( format == RTAUDIO_FLOAT64 )\r
+    deviceFormat = SND_PCM_FORMAT_FLOAT64;\r
+\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) {\r
+    stream_.deviceFormat[mode] = format;\r
+    goto setFormat;\r
+  }\r
+\r
+  // The user requested format is not natively supported by the device.\r
+  deviceFormat = SND_PCM_FORMAT_FLOAT64;\r
+  if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;\r
+    goto setFormat;\r
+  }\r
+\r
+  deviceFormat = SND_PCM_FORMAT_FLOAT;\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
+    goto setFormat;\r
+  }\r
+\r
+  deviceFormat = SND_PCM_FORMAT_S32;\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+    goto setFormat;\r
+  }\r
+\r
+  deviceFormat = SND_PCM_FORMAT_S24;\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+    goto setFormat;\r
+  }\r
+\r
+  deviceFormat = SND_PCM_FORMAT_S16;\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+    goto setFormat;\r
+  }\r
+\r
+  deviceFormat = SND_PCM_FORMAT_S8;\r
+  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
+    stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+    goto setFormat;\r
+  }\r
+\r
+  // If we get here, no supported format was found.\r
+  snd_pcm_close( phandle );\r
+  errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio.";\r
+  errorText_ = errorStream_.str();\r
+  return FAILURE;\r
+\r
+ setFormat:\r
+  result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Determine whether byte-swaping is necessary.\r
+  stream_.doByteSwap[mode] = false;\r
+  if ( deviceFormat != SND_PCM_FORMAT_S8 ) {\r
+    result = snd_pcm_format_cpu_endian( deviceFormat );\r
+    if ( result == 0 )\r
+      stream_.doByteSwap[mode] = true;\r
+    else if (result < 0) {\r
+      snd_pcm_close( phandle );\r
+      errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      return FAILURE;\r
+    }\r
+  }\r
+\r
+  // Set the sample rate.\r
+  result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Determine the number of channels for this device.  We support a possible\r
+  // minimum device channel number > than the value requested by the user.\r
+  stream_.nUserChannels[mode] = channels;\r
+  unsigned int value;\r
+  result = snd_pcm_hw_params_get_channels_max( hw_params, &value );\r
+  unsigned int deviceChannels = value;\r
+  if ( result < 0 || deviceChannels < channels + firstChannel ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  result = snd_pcm_hw_params_get_channels_min( hw_params, &value );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  deviceChannels = value;\r
+  if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel;\r
+  stream_.nDeviceChannels[mode] = deviceChannels;\r
+\r
+  // Set the device channels.\r
+  result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the buffer (or period) size.\r
+  int dir = 0;\r
+  snd_pcm_uframes_t periodSize = *bufferSize;\r
+  result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  *bufferSize = periodSize;\r
+\r
+  // Set the buffer number, which in ALSA is referred to as the "period".\r
+  unsigned int periods = 0;\r
+  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;\r
+  if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers;\r
+  if ( periods < 2 ) periods = 4; // a fairly safe default value\r
+  result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // If attempting to setup a duplex stream, the bufferSize parameter\r
+  // MUST be the same in both directions!\r
+  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  stream_.bufferSize = *bufferSize;\r
+\r
+  // Install the hardware configuration\r
+  result = snd_pcm_hw_params( phandle, hw_params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+#if defined(__RTAUDIO_DEBUG__)\r
+  fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");\r
+  snd_pcm_hw_params_dump( hw_params, out );\r
+#endif\r
+\r
+  // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.\r
+  snd_pcm_sw_params_t *sw_params = NULL;\r
+  snd_pcm_sw_params_alloca( &sw_params );\r
+  snd_pcm_sw_params_current( phandle, sw_params );\r
+  snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );\r
+  snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );\r
+  snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );\r
+\r
+  // The following two settings were suggested by Theo Veenker\r
+  //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );\r
+  //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );\r
+\r
+  // here are two options for a fix\r
+  //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );\r
+  snd_pcm_uframes_t val;\r
+  snd_pcm_sw_params_get_boundary( sw_params, &val );\r
+  snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );\r
+\r
+  result = snd_pcm_sw_params( phandle, sw_params );\r
+  if ( result < 0 ) {\r
+    snd_pcm_close( phandle );\r
+    errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << ".";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+#if defined(__RTAUDIO_DEBUG__)\r
+  fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");\r
+  snd_pcm_sw_params_dump( sw_params, out );\r
+#endif\r
+\r
+  // Set flags for buffer conversion\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+       stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate the ApiHandle if necessary and then save.\r
+  AlsaHandle *apiInfo = 0;\r
+  if ( stream_.apiHandle == 0 ) {\r
+    try {\r
+      apiInfo = (AlsaHandle *) new AlsaHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";\r
+      goto error;\r
+    }\r
+\r
+    if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {\r
+      errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";\r
+      goto error;\r
+    }\r
+\r
+    stream_.apiHandle = (void *) apiInfo;\r
+    apiInfo->handles[0] = 0;\r
+    apiInfo->handles[1] = 0;\r
+  }\r
+  else {\r
+    apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  }\r
+  apiInfo->handles[mode] = phandle;\r
+  phandle = 0;\r
+\r
+  // Allocate necessary internal buffers.\r
+  unsigned long bufferBytes;\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.sampleRate = sampleRate;\r
+  stream_.nBuffers = periods;\r
+  stream_.device[mode] = device;\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
+  // Setup thread if necessary.\r
+  if ( stream_.mode == OUTPUT && mode == INPUT ) {\r
+    // We had already set up an output stream.\r
+    stream_.mode = DUPLEX;\r
+    // Link the streams if possible.\r
+    apiInfo->synchronized = false;\r
+    if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 )\r
+      apiInfo->synchronized = true;\r
+    else {\r
+      errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";\r
+      error( RtAudioError::WARNING );\r
+    }\r
+  }\r
+  else {\r
+    stream_.mode = mode;\r
+\r
+    // Setup callback thread.\r
+    stream_.callbackInfo.object = (void *) this;\r
+\r
+    // Set the thread attributes for joinable and realtime scheduling\r
+    // priority (optional).  The higher priority will only take affect\r
+    // if the program is run as root or suid. Note, under Linux\r
+    // processes with CAP_SYS_NICE privilege, a user can change\r
+    // scheduling policy and priority (thus need not be root). See\r
+    // POSIX "capabilities".\r
+    pthread_attr_t attr;\r
+    pthread_attr_init( &attr );\r
+    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );\r
+\r
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
+    if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {\r
+      // We previously attempted to increase the audio callback priority\r
+      // to SCHED_RR here via the attributes.  However, while no errors\r
+      // were reported in doing so, it did not work.  So, now this is\r
+      // done in the alsaCallbackHandler function.\r
+      stream_.callbackInfo.doRealtime = true;\r
+      int priority = options->priority;\r
+      int min = sched_get_priority_min( SCHED_RR );\r
+      int max = sched_get_priority_max( SCHED_RR );\r
+      if ( priority < min ) priority = min;\r
+      else if ( priority > max ) priority = max;\r
+      stream_.callbackInfo.priority = priority;\r
+    }\r
+#endif\r
+\r
+    stream_.callbackInfo.isRunning = true;\r
+    result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );\r
+    pthread_attr_destroy( &attr );\r
+    if ( result ) {\r
+      stream_.callbackInfo.isRunning = false;\r
+      errorText_ = "RtApiAlsa::error creating callback thread!";\r
+      goto error;\r
+    }\r
+  }\r
+\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( apiInfo ) {\r
+    pthread_cond_destroy( &apiInfo->runnable_cv );\r
+    if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
+    if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
+    delete apiInfo;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  if ( phandle) snd_pcm_close( phandle );\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.state = STREAM_CLOSED;\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiAlsa :: closeStream()\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  stream_.callbackInfo.isRunning = false;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    apiInfo->runnable = true;\r
+    pthread_cond_signal( &apiInfo->runnable_cv );\r
+  }\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+  pthread_join( stream_.callbackInfo.thread, NULL );\r
+\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    stream_.state = STREAM_STOPPED;\r
+    if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
+      snd_pcm_drop( apiInfo->handles[0] );\r
+    if ( stream_.mode == INPUT || stream_.mode == DUPLEX )\r
+      snd_pcm_drop( apiInfo->handles[1] );\r
+  }\r
+\r
+  if ( apiInfo ) {\r
+    pthread_cond_destroy( &apiInfo->runnable_cv );\r
+    if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
+    if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
+    delete apiInfo;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+void RtApiAlsa :: startStream()\r
+{\r
+  // This method calls snd_pcm_prepare if the device isn't already in that state.\r
+\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiAlsa::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  int result = 0;\r
+  snd_pcm_state_t state;\r
+  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    state = snd_pcm_state( handle[0] );\r
+    if ( state != SND_PCM_STATE_PREPARED ) {\r
+      result = snd_pcm_prepare( handle[0] );\r
+      if ( result < 0 ) {\r
+        errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+        goto unlock;\r
+      }\r
+    }\r
+  }\r
+\r
+  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
+    result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open\r
+    state = snd_pcm_state( handle[1] );\r
+    if ( state != SND_PCM_STATE_PREPARED ) {\r
+      result = snd_pcm_prepare( handle[1] );\r
+      if ( result < 0 ) {\r
+        errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+        goto unlock;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+ unlock:\r
+  apiInfo->runnable = true;\r
+  pthread_cond_signal( &apiInfo->runnable_cv );\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( result >= 0 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiAlsa :: stopStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  int result = 0;\r
+  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( apiInfo->synchronized ) \r
+      result = snd_pcm_drop( handle[0] );\r
+    else\r
+      result = snd_pcm_drain( handle[0] );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
+    result = snd_pcm_drop( handle[1] );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( result >= 0 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiAlsa :: abortStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  int result = 0;\r
+  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    result = snd_pcm_drop( handle[0] );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
+    result = snd_pcm_drop( handle[1] );\r
+    if ( result < 0 ) {\r
+      errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( result >= 0 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiAlsa :: callbackEvent()\r
+{\r
+  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_LOCK( &stream_.mutex );\r
+    while ( !apiInfo->runnable )\r
+      pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );\r
+\r
+    if ( stream_.state != STREAM_RUNNING ) {\r
+      MUTEX_UNLOCK( &stream_.mutex );\r
+      return;\r
+    }\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+  }\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  int doStopStream = 0;\r
+  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
+  double streamTime = getStreamTime();\r
+  RtAudioStreamStatus status = 0;\r
+  if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) {\r
+    status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+    apiInfo->xrun[0] = false;\r
+  }\r
+  if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) {\r
+    status |= RTAUDIO_INPUT_OVERFLOW;\r
+    apiInfo->xrun[1] = false;\r
+  }\r
+  doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                           stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );\r
+\r
+  if ( doStopStream == 2 ) {\r
+    abortStream();\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  // The state might change while waiting on a mutex.\r
+  if ( stream_.state == STREAM_STOPPED ) goto unlock;\r
+\r
+  int result;\r
+  char *buffer;\r
+  int channels;\r
+  snd_pcm_t **handle;\r
+  snd_pcm_sframes_t frames;\r
+  RtAudioFormat format;\r
+  handle = (snd_pcm_t **) apiInfo->handles;\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Setup parameters.\r
+    if ( stream_.doConvertBuffer[1] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      channels = stream_.nDeviceChannels[1];\r
+      format = stream_.deviceFormat[1];\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[1];\r
+      channels = stream_.nUserChannels[1];\r
+      format = stream_.userFormat;\r
+    }\r
+\r
+    // Read samples from device in interleaved/non-interleaved format.\r
+    if ( stream_.deviceInterleaved[1] )\r
+      result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize );\r
+    else {\r
+      void *bufs[channels];\r
+      size_t offset = stream_.bufferSize * formatBytes( format );\r
+      for ( int i=0; i<channels; i++ )\r
+        bufs[i] = (void *) (buffer + (i * offset));\r
+      result = snd_pcm_readn( handle[1], bufs, stream_.bufferSize );\r
+    }\r
+\r
+    if ( result < (int) stream_.bufferSize ) {\r
+      // Either an error or overrun occured.\r
+      if ( result == -EPIPE ) {\r
+        snd_pcm_state_t state = snd_pcm_state( handle[1] );\r
+        if ( state == SND_PCM_STATE_XRUN ) {\r
+          apiInfo->xrun[1] = true;\r
+          result = snd_pcm_prepare( handle[1] );\r
+          if ( result < 0 ) {\r
+            errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << ".";\r
+            errorText_ = errorStream_.str();\r
+          }\r
+        }\r
+        else {\r
+          errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";\r
+          errorText_ = errorStream_.str();\r
+        }\r
+      }\r
+      else {\r
+        errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+      }\r
+      error( RtAudioError::WARNING );\r
+      goto tryOutput;\r
+    }\r
+\r
+    // Do byte swapping if necessary.\r
+    if ( stream_.doByteSwap[1] )\r
+      byteSwapBuffer( buffer, stream_.bufferSize * channels, format );\r
+\r
+    // Do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[1] )\r
+      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
+\r
+    // Check stream latency\r
+    result = snd_pcm_delay( handle[1], &frames );\r
+    if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;\r
+  }\r
+\r
+ tryOutput:\r
+\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Setup parameters and do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[0] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+      channels = stream_.nDeviceChannels[0];\r
+      format = stream_.deviceFormat[0];\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[0];\r
+      channels = stream_.nUserChannels[0];\r
+      format = stream_.userFormat;\r
+    }\r
+\r
+    // Do byte swapping if necessary.\r
+    if ( stream_.doByteSwap[0] )\r
+      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);\r
+\r
+    // Write samples to device in interleaved/non-interleaved format.\r
+    if ( stream_.deviceInterleaved[0] )\r
+      result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize );\r
+    else {\r
+      void *bufs[channels];\r
+      size_t offset = stream_.bufferSize * formatBytes( format );\r
+      for ( int i=0; i<channels; i++ )\r
+        bufs[i] = (void *) (buffer + (i * offset));\r
+      result = snd_pcm_writen( handle[0], bufs, stream_.bufferSize );\r
+    }\r
+\r
+    if ( result < (int) stream_.bufferSize ) {\r
+      // Either an error or underrun occured.\r
+      if ( result == -EPIPE ) {\r
+        snd_pcm_state_t state = snd_pcm_state( handle[0] );\r
+        if ( state == SND_PCM_STATE_XRUN ) {\r
+          apiInfo->xrun[0] = true;\r
+          result = snd_pcm_prepare( handle[0] );\r
+          if ( result < 0 ) {\r
+            errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";\r
+            errorText_ = errorStream_.str();\r
+          }\r
+        }\r
+        else {\r
+          errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";\r
+          errorText_ = errorStream_.str();\r
+        }\r
+      }\r
+      else {\r
+        errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";\r
+        errorText_ = errorStream_.str();\r
+      }\r
+      error( RtAudioError::WARNING );\r
+      goto unlock;\r
+    }\r
+\r
+    // Check stream latency\r
+    result = snd_pcm_delay( handle[0], &frames );\r
+    if ( result == 0 && frames > 0 ) stream_.latency[0] = frames;\r
+  }\r
+\r
+ unlock:\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  RtApi::tickStreamTime();\r
+  if ( doStopStream == 1 ) this->stopStream();\r
+}\r
+\r
+static void *alsaCallbackHandler( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiAlsa *object = (RtApiAlsa *) info->object;\r
+  bool *isRunning = &info->isRunning;\r
+\r
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
+  if ( &info->doRealtime ) {\r
+    pthread_t tID = pthread_self();     // ID of this thread\r
+    sched_param prio = { info->priority }; // scheduling priority of thread\r
+    pthread_setschedparam( tID, SCHED_RR, &prio );\r
+  }\r
+#endif\r
+\r
+  while ( *isRunning == true ) {\r
+    pthread_testcancel();\r
+    object->callbackEvent();\r
+  }\r
+\r
+  pthread_exit( NULL );\r
+}\r
+\r
+//******************** End of __LINUX_ALSA__ *********************//\r
+#endif\r
+\r
+#if defined(__LINUX_PULSE__)\r
+\r
+// Code written by Peter Meerwald, pmeerw@pmeerw.net\r
+// and Tristan Matthews.\r
+\r
+#include <pulse/error.h>\r
+#include <pulse/simple.h>\r
+#include <cstdio>\r
+\r
+static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
+                                                      44100, 48000, 96000, 0};\r
+\r
+struct rtaudio_pa_format_mapping_t {\r
+  RtAudioFormat rtaudio_format;\r
+  pa_sample_format_t pa_format;\r
+};\r
+\r
+static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {\r
+  {RTAUDIO_SINT16, PA_SAMPLE_S16LE},\r
+  {RTAUDIO_SINT32, PA_SAMPLE_S32LE},\r
+  {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},\r
+  {0, PA_SAMPLE_INVALID}};\r
+\r
+struct PulseAudioHandle {\r
+  pa_simple *s_play;\r
+  pa_simple *s_rec;\r
+  pthread_t thread;\r
+  pthread_cond_t runnable_cv;\r
+  bool runnable;\r
+  PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { }\r
+};\r
+\r
+RtApiPulse::~RtApiPulse()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED )\r
+    closeStream();\r
+}\r
+\r
+unsigned int RtApiPulse::getDeviceCount( void )\r
+{\r
+  return 1;\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = true;\r
+  info.name = "PulseAudio";\r
+  info.outputChannels = 2;\r
+  info.inputChannels = 2;\r
+  info.duplexChannels = 2;\r
+  info.isDefaultOutput = true;\r
+  info.isDefaultInput = true;\r
+\r
+  for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )\r
+    info.sampleRates.push_back( *sr );\r
+\r
+  info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;\r
+\r
+  return info;\r
+}\r
+\r
+static void *pulseaudio_callback( void * user )\r
+{\r
+  CallbackInfo *cbi = static_cast<CallbackInfo *>( user );\r
+  RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );\r
+  volatile bool *isRunning = &cbi->isRunning;\r
+\r
+  while ( *isRunning ) {\r
+    pthread_testcancel();\r
+    context->callbackEvent();\r
+  }\r
+\r
+  pthread_exit( NULL );\r
+}\r
+\r
+void RtApiPulse::closeStream( void )\r
+{\r
+  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
+\r
+  stream_.callbackInfo.isRunning = false;\r
+  if ( pah ) {\r
+    MUTEX_LOCK( &stream_.mutex );\r
+    if ( stream_.state == STREAM_STOPPED ) {\r
+      pah->runnable = true;\r
+      pthread_cond_signal( &pah->runnable_cv );\r
+    }\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+    pthread_join( pah->thread, 0 );\r
+    if ( pah->s_play ) {\r
+      pa_simple_flush( pah->s_play, NULL );\r
+      pa_simple_free( pah->s_play );\r
+    }\r
+    if ( pah->s_rec )\r
+      pa_simple_free( pah->s_rec );\r
+\r
+    pthread_cond_destroy( &pah->runnable_cv );\r
+    delete pah;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  if ( stream_.userBuffer[0] ) {\r
+    free( stream_.userBuffer[0] );\r
+    stream_.userBuffer[0] = 0;\r
+  }\r
+  if ( stream_.userBuffer[1] ) {\r
+    free( stream_.userBuffer[1] );\r
+    stream_.userBuffer[1] = 0;\r
+  }\r
+\r
+  stream_.state = STREAM_CLOSED;\r
+  stream_.mode = UNINITIALIZED;\r
+}\r
+\r
+void RtApiPulse::callbackEvent( void )\r
+{\r
+  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
+\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_LOCK( &stream_.mutex );\r
+    while ( !pah->runnable )\r
+      pthread_cond_wait( &pah->runnable_cv, &stream_.mutex );\r
+\r
+    if ( stream_.state != STREAM_RUNNING ) {\r
+      MUTEX_UNLOCK( &stream_.mutex );\r
+      return;\r
+    }\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+  }\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "\r
+      "this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
+  double streamTime = getStreamTime();\r
+  RtAudioStreamStatus status = 0;\r
+  int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],\r
+                               stream_.bufferSize, streamTime, status,\r
+                               stream_.callbackInfo.userData );\r
+\r
+  if ( doStopStream == 2 ) {\r
+    abortStream();\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+  void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];\r
+  void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];\r
+\r
+  if ( stream_.state != STREAM_RUNNING )\r
+    goto unlock;\r
+\r
+  int pa_error;\r
+  size_t bytes;\r
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( stream_.doConvertBuffer[OUTPUT] ) {\r
+        convertBuffer( stream_.deviceBuffer,\r
+                       stream_.userBuffer[OUTPUT],\r
+                       stream_.convertInfo[OUTPUT] );\r
+        bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *\r
+                formatBytes( stream_.deviceFormat[OUTPUT] );\r
+    } else\r
+        bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *\r
+                formatBytes( stream_.userFormat );\r
+\r
+    if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {\r
+      errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
+        pa_strerror( pa_error ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::WARNING );\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {\r
+    if ( stream_.doConvertBuffer[INPUT] )\r
+      bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *\r
+        formatBytes( stream_.deviceFormat[INPUT] );\r
+    else\r
+      bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *\r
+        formatBytes( stream_.userFormat );\r
+            \r
+    if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {\r
+      errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
+        pa_strerror( pa_error ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      error( RtAudioError::WARNING );\r
+    }\r
+    if ( stream_.doConvertBuffer[INPUT] ) {\r
+      convertBuffer( stream_.userBuffer[INPUT],\r
+                     stream_.deviceBuffer,\r
+                     stream_.convertInfo[INPUT] );\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+  RtApi::tickStreamTime();\r
+\r
+  if ( doStopStream == 1 )\r
+    stopStream();\r
+}\r
+\r
+void RtApiPulse::startStream( void )\r
+{\r
+  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiPulse::startStream(): the stream is not open!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiPulse::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+  pah->runnable = true;\r
+  pthread_cond_signal( &pah->runnable_cv );\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+}\r
+\r
+void RtApiPulse::stopStream( void )\r
+{\r
+  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiPulse::stopStream(): the stream is not open!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  if ( pah && pah->s_play ) {\r
+    int pa_error;\r
+    if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {\r
+      errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<\r
+        pa_strerror( pa_error ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      MUTEX_UNLOCK( &stream_.mutex );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+}\r
+\r
+void RtApiPulse::abortStream( void )\r
+{\r
+  PulseAudioHandle *pah = static_cast<PulseAudioHandle*>( stream_.apiHandle );\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiPulse::abortStream(): the stream is not open!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
+  }\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  if ( pah && pah->s_play ) {\r
+    int pa_error;\r
+    if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {\r
+      errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<\r
+        pa_strerror( pa_error ) << ".";\r
+      errorText_ = errorStream_.str();\r
+      MUTEX_UNLOCK( &stream_.mutex );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+}\r
+\r
+bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,\r
+                                  unsigned int channels, unsigned int firstChannel,\r
+                                  unsigned int sampleRate, RtAudioFormat format,\r
+                                  unsigned int *bufferSize, RtAudio::StreamOptions *options )\r
+{\r
+  PulseAudioHandle *pah = 0;\r
+  unsigned long bufferBytes = 0;\r
+  pa_sample_spec ss;\r
+\r
+  if ( device != 0 ) return false;\r
+  if ( mode != INPUT && mode != OUTPUT ) return false;\r
+  if ( channels != 1 && channels != 2 ) {\r
+    errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";\r
+    return false;\r
+  }\r
+  ss.channels = channels;\r
+\r
+  if ( firstChannel != 0 ) return false;\r
+\r
+  bool sr_found = false;\r
+  for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) {\r
+    if ( sampleRate == *sr ) {\r
+      sr_found = true;\r
+      stream_.sampleRate = sampleRate;\r
+      ss.rate = sampleRate;\r
+      break;\r
+    }\r
+  }\r
+  if ( !sr_found ) {\r
+    errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate.";\r
+    return false;\r
+  }\r
+\r
+  bool sf_found = 0;\r
+  for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;\r
+        sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) {\r
+    if ( format == sf->rtaudio_format ) {\r
+      sf_found = true;\r
+      stream_.userFormat = sf->rtaudio_format;\r
+      stream_.deviceFormat[mode] = stream_.userFormat;\r
+      ss.format = sf->pa_format;\r
+      break;\r
+    }\r
+  }\r
+  if ( !sf_found ) { // Use internal data format conversion.\r
+    stream_.userFormat = format;\r
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
+    ss.format = PA_SAMPLE_FLOAT32LE;\r
+  }\r
+\r
+  // Set other stream parameters.\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
+  stream_.deviceInterleaved[mode] = true;\r
+  stream_.nBuffers = 1;\r
+  stream_.doByteSwap[mode] = false;\r
+  stream_.nUserChannels[mode] = channels;\r
+  stream_.nDeviceChannels[mode] = channels + firstChannel;\r
+  stream_.channelOffset[mode] = 0;\r
+  std::string streamName = "RtAudio";\r
+\r
+  // Set flags for buffer conversion.\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate necessary internal buffers.\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+  stream_.bufferSize = *bufferSize;\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.device[mode] = device;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
+  if ( !stream_.apiHandle ) {\r
+    PulseAudioHandle *pah = new PulseAudioHandle;\r
+    if ( !pah ) {\r
+      errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle.";\r
+      goto error;\r
+    }\r
+\r
+    stream_.apiHandle = pah;\r
+    if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) {\r
+      errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable.";\r
+      goto error;\r
+    }\r
+  }\r
+  pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
+\r
+  int error;\r
+  if ( !options->streamName.empty() ) streamName = options->streamName;\r
+  switch ( mode ) {\r
+  case INPUT:\r
+    pa_buffer_attr buffer_attr;\r
+    buffer_attr.fragsize = bufferBytes;\r
+    buffer_attr.maxlength = -1;\r
+\r
+    pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );\r
+    if ( !pah->s_rec ) {\r
+      errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";\r
+      goto error;\r
+    }\r
+    break;\r
+  case OUTPUT:\r
+    pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );\r
+    if ( !pah->s_play ) {\r
+      errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";\r
+      goto error;\r
+    }\r
+    break;\r
+  default:\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.mode == UNINITIALIZED )\r
+    stream_.mode = mode;\r
+  else if ( stream_.mode == mode )\r
+    goto error;\r
+  else\r
+    stream_.mode = DUPLEX;\r
+\r
+  if ( !stream_.callbackInfo.isRunning ) {\r
+    stream_.callbackInfo.object = this;\r
+    stream_.callbackInfo.isRunning = true;\r
+    if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {\r
+      errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";\r
+      goto error;\r
+    }\r
+  }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
+  return true;\r
\r
+ error:\r
+  if ( pah && stream_.callbackInfo.isRunning ) {\r
+    pthread_cond_destroy( &pah->runnable_cv );\r
+    delete pah;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  return FAILURE;\r
+}\r
+\r
+//******************** End of __LINUX_PULSE__ *********************//\r
+#endif\r
+\r
+#if defined(__LINUX_OSS__)\r
+\r
+#include <unistd.h>\r
+#include <sys/ioctl.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <sys/soundcard.h>\r
+#include <errno.h>\r
+#include <math.h>\r
+\r
+static void *ossCallbackHandler(void * ptr);\r
+\r
+// A structure to hold various information related to the OSS API\r
+// implementation.\r
+struct OssHandle {\r
+  int id[2];    // device ids\r
+  bool xrun[2];\r
+  bool triggered;\r
+  pthread_cond_t runnable;\r
+\r
+  OssHandle()\r
+    :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
+};\r
+\r
+RtApiOss :: RtApiOss()\r
+{\r
+  // Nothing to do here.\r
+}\r
+\r
+RtApiOss :: ~RtApiOss()\r
+{\r
+  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+}\r
+\r
+unsigned int RtApiOss :: getDeviceCount( void )\r
+{\r
+  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
+  if ( mixerfd == -1 ) {\r
+    errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  oss_sysinfo sysinfo;\r
+  if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";\r
+    error( RtAudioError::WARNING );\r
+    return 0;\r
+  }\r
+\r
+  close( mixerfd );\r
+  return sysinfo.numaudios;\r
+}\r
+\r
+RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )\r
+{\r
+  RtAudio::DeviceInfo info;\r
+  info.probed = false;\r
+\r
+  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
+  if ( mixerfd == -1 ) {\r
+    errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  oss_sysinfo sysinfo;\r
+  int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );\r
+  if ( result == -1 ) {\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  unsigned nDevices = sysinfo.numaudios;\r
+  if ( nDevices == 0 ) {\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::getDeviceInfo: no devices found!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
+  }\r
+\r
+  oss_audioinfo ainfo;\r
+  ainfo.dev = device;\r
+  result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );\r
+  close( mixerfd );\r
+  if ( result == -1 ) {\r
+    errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Probe channels\r
+  if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels;\r
+  if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels;\r
+  if ( ainfo.caps & PCM_CAP_DUPLEX ) {\r
+    if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX )\r
+      info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
+  }\r
+\r
+  // Probe data formats ... do for input\r
+  unsigned long mask = ainfo.iformats;\r
+  if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE )\r
+    info.nativeFormats |= RTAUDIO_SINT16;\r
+  if ( mask & AFMT_S8 )\r
+    info.nativeFormats |= RTAUDIO_SINT8;\r
+  if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )\r
+    info.nativeFormats |= RTAUDIO_SINT32;\r
+  if ( mask & AFMT_FLOAT )\r
+    info.nativeFormats |= RTAUDIO_FLOAT32;\r
+  if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )\r
+    info.nativeFormats |= RTAUDIO_SINT24;\r
+\r
+  // Check that we have at least one supported format\r
+  if ( info.nativeFormats == 0 ) {\r
+    errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+    return info;\r
+  }\r
+\r
+  // Probe the supported sample rates.\r
+  info.sampleRates.clear();\r
+  if ( ainfo.nrates ) {\r
+    for ( unsigned int i=0; i<ainfo.nrates; i++ ) {\r
+      for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
+        if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {\r
+          info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  else {\r
+    // Check min and max rate values;\r
+    for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
+      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] )\r
+        info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+    }\r
+  }\r
+\r
+  if ( info.sampleRates.size() == 0 ) {\r
+    errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    error( RtAudioError::WARNING );\r
+  }\r
+  else {\r
+    info.probed = true;\r
+    info.name = ainfo.name;\r
+  }\r
+\r
+  return info;\r
+}\r
+\r
+\r
+bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
+                                  unsigned int firstChannel, unsigned int sampleRate,\r
+                                  RtAudioFormat format, unsigned int *bufferSize,\r
+                                  RtAudio::StreamOptions *options )\r
+{\r
+  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
+  if ( mixerfd == -1 ) {\r
+    errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'.";\r
+    return FAILURE;\r
+  }\r
+\r
+  oss_sysinfo sysinfo;\r
+  int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );\r
+  if ( result == -1 ) {\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required.";\r
+    return FAILURE;\r
+  }\r
+\r
+  unsigned nDevices = sysinfo.numaudios;\r
+  if ( nDevices == 0 ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::probeDeviceOpen: no devices found!";\r
+    return FAILURE;\r
+  }\r
+\r
+  if ( device >= nDevices ) {\r
+    // This should not happen because a check is made before this function is called.\r
+    close( mixerfd );\r
+    errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!";\r
+    return FAILURE;\r
+  }\r
+\r
+  oss_audioinfo ainfo;\r
+  ainfo.dev = device;\r
+  result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );\r
+  close( mixerfd );\r
+  if ( result == -1 ) {\r
+    errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Check if device supports input or output\r
+  if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) ||\r
+       ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) {\r
+    if ( mode == OUTPUT )\r
+      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output.";\r
+    else\r
+      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  int flags = 0;\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  if ( mode == OUTPUT )\r
+    flags |= O_WRONLY;\r
+  else { // mode == INPUT\r
+    if (stream_.mode == OUTPUT && stream_.device[0] == device) {\r
+      // We just set the same device for playback ... close and reopen for duplex (OSS only).\r
+      close( handle->id[0] );\r
+      handle->id[0] = 0;\r
+      if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) {\r
+        errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode.";\r
+        errorText_ = errorStream_.str();\r
+        return FAILURE;\r
+      }\r
+      // Check that the number previously set channels is the same.\r
+      if ( stream_.nUserChannels[0] != channels ) {\r
+        errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ").";\r
+        errorText_ = errorStream_.str();\r
+        return FAILURE;\r
+      }\r
+      flags |= O_RDWR;\r
+    }\r
+    else\r
+      flags |= O_RDONLY;\r
+  }\r
+\r
+  // Set exclusive access if specified.\r
+  if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL;\r
+\r
+  // Try to open the device.\r
+  int fd;\r
+  fd = open( ainfo.devnode, flags, 0 );\r
+  if ( fd == -1 ) {\r
+    if ( errno == EBUSY )\r
+      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy.";\r
+    else\r
+      errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // For duplex operation, specifically set this mode (this doesn't seem to work).\r
+  /*\r
+    if ( flags | O_RDWR ) {\r
+    result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );\r
+    if ( result == -1) {\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+    }\r
+    }\r
+  */\r
+\r
+  // Check the device channel support.\r
+  stream_.nUserChannels[mode] = channels;\r
+  if ( ainfo.max_channels < (int)(channels + firstChannel) ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the number of channels.\r
+  int deviceChannels = channels + firstChannel;\r
+  result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels );\r
+  if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  stream_.nDeviceChannels[mode] = deviceChannels;\r
+\r
+  // Get the data format mask\r
+  int mask;\r
+  result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask );\r
+  if ( result == -1 ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Determine how to set the device format.\r
+  stream_.userFormat = format;\r
+  int deviceFormat = -1;\r
+  stream_.doByteSwap[mode] = false;\r
+  if ( format == RTAUDIO_SINT8 ) {\r
+    if ( mask & AFMT_S8 ) {\r
+      deviceFormat = AFMT_S8;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_SINT16 ) {\r
+    if ( mask & AFMT_S16_NE ) {\r
+      deviceFormat = AFMT_S16_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+    }\r
+    else if ( mask & AFMT_S16_OE ) {\r
+      deviceFormat = AFMT_S16_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_SINT24 ) {\r
+    if ( mask & AFMT_S24_NE ) {\r
+      deviceFormat = AFMT_S24_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+    }\r
+    else if ( mask & AFMT_S24_OE ) {\r
+      deviceFormat = AFMT_S24_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_SINT32 ) {\r
+    if ( mask & AFMT_S32_NE ) {\r
+      deviceFormat = AFMT_S32_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+    }\r
+    else if ( mask & AFMT_S32_OE ) {\r
+      deviceFormat = AFMT_S32_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+  }\r
+\r
+  if ( deviceFormat == -1 ) {\r
+    // The user requested format is not natively supported by the device.\r
+    if ( mask & AFMT_S16_NE ) {\r
+      deviceFormat = AFMT_S16_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+    }\r
+    else if ( mask & AFMT_S32_NE ) {\r
+      deviceFormat = AFMT_S32_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+    }\r
+    else if ( mask & AFMT_S24_NE ) {\r
+      deviceFormat = AFMT_S24_NE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+    }\r
+    else if ( mask & AFMT_S16_OE ) {\r
+      deviceFormat = AFMT_S16_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+    else if ( mask & AFMT_S32_OE ) {\r
+      deviceFormat = AFMT_S32_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+    else if ( mask & AFMT_S24_OE ) {\r
+      deviceFormat = AFMT_S24_OE;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
+      stream_.doByteSwap[mode] = true;\r
+    }\r
+    else if ( mask & AFMT_S8) {\r
+      deviceFormat = AFMT_S8;\r
+      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceFormat[mode] == 0 ) {\r
+    // This really shouldn't happen ...\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio.";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Set the data format.\r
+  int temp = deviceFormat;\r
+  result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat );\r
+  if ( result == -1 || deviceFormat != temp ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Attempt to set the buffer size.  According to OSS, the minimum\r
+  // number of buffers is two.  The supposed minimum buffer size is 16\r
+  // bytes, so that will be our lower bound.  The argument to this\r
+  // call is in the form 0xMMMMSSSS (hex), where the buffer size (in\r
+  // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.\r
+  // We'll check the actual value used near the end of the setup\r
+  // procedure.\r
+  int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels;\r
+  if ( ossBufferBytes < 16 ) ossBufferBytes = 16;\r
+  int buffers = 0;\r
+  if ( options ) buffers = options->numberOfBuffers;\r
+  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2;\r
+  if ( buffers < 2 ) buffers = 3;\r
+  temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) );\r
+  result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp );\r
+  if ( result == -1 ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  stream_.nBuffers = buffers;\r
+\r
+  // Save buffer size (in sample frames).\r
+  *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels );\r
+  stream_.bufferSize = *bufferSize;\r
+\r
+  // Set the sample rate.\r
+  int srate = sampleRate;\r
+  result = ioctl( fd, SNDCTL_DSP_SPEED, &srate );\r
+  if ( result == -1 ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+\r
+  // Verify the sample rate setup worked.\r
+  if ( abs( srate - sampleRate ) > 100 ) {\r
+    close( fd );\r
+    errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";\r
+    errorText_ = errorStream_.str();\r
+    return FAILURE;\r
+  }\r
+  stream_.sampleRate = sampleRate;\r
+\r
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) {\r
+    // We're doing duplex setup here.\r
+    stream_.deviceFormat[0] = stream_.deviceFormat[1];\r
+    stream_.nDeviceChannels[0] = deviceChannels;\r
+  }\r
+\r
+  // Set interleaving parameters.\r
+  stream_.userInterleaved = true;\r
+  stream_.deviceInterleaved[mode] =  true;\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED )\r
+    stream_.userInterleaved = false;\r
+\r
+  // Set flags for buffer conversion\r
+  stream_.doConvertBuffer[mode] = false;\r
+  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
+    stream_.doConvertBuffer[mode] = true;\r
+  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+       stream_.nUserChannels[mode] > 1 )\r
+    stream_.doConvertBuffer[mode] = true;\r
+\r
+  // Allocate the stream handles if necessary and then save.\r
+  if ( stream_.apiHandle == 0 ) {\r
+    try {\r
+      handle = new OssHandle;\r
+    }\r
+    catch ( std::bad_alloc& ) {\r
+      errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory.";\r
+      goto error;\r
+    }\r
+\r
+    if ( pthread_cond_init( &handle->runnable, NULL ) ) {\r
+      errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";\r
+      goto error;\r
+    }\r
+\r
+    stream_.apiHandle = (void *) handle;\r
+  }\r
+  else {\r
+    handle = (OssHandle *) stream_.apiHandle;\r
+  }\r
+  handle->id[mode] = fd;\r
+\r
+  // Allocate necessary internal buffers.\r
+  unsigned long bufferBytes;\r
+  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
+  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
+  if ( stream_.userBuffer[mode] == NULL ) {\r
+    errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory.";\r
+    goto error;\r
+  }\r
+\r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.device[mode] = device;\r
+  stream_.state = STREAM_STOPPED;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
+  // Setup thread if necessary.\r
+  if ( stream_.mode == OUTPUT && mode == INPUT ) {\r
+    // We had already set up an output stream.\r
+    stream_.mode = DUPLEX;\r
+    if ( stream_.device[0] == device ) handle->id[0] = fd;\r
+  }\r
+  else {\r
+    stream_.mode = mode;\r
+\r
+    // Setup callback thread.\r
+    stream_.callbackInfo.object = (void *) this;\r
+\r
+    // Set the thread attributes for joinable and realtime scheduling\r
+    // priority.  The higher priority will only take affect if the\r
+    // program is run as root or suid.\r
+    pthread_attr_t attr;\r
+    pthread_attr_init( &attr );\r
+    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );\r
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
+    if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {\r
+      struct sched_param param;\r
+      int priority = options->priority;\r
+      int min = sched_get_priority_min( SCHED_RR );\r
+      int max = sched_get_priority_max( SCHED_RR );\r
+      if ( priority < min ) priority = min;\r
+      else if ( priority > max ) priority = max;\r
+      param.sched_priority = priority;\r
+      pthread_attr_setschedparam( &attr, &param );\r
+      pthread_attr_setschedpolicy( &attr, SCHED_RR );\r
+    }\r
+    else\r
+      pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
+#else\r
+    pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
+#endif\r
+\r
+    stream_.callbackInfo.isRunning = true;\r
+    result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );\r
+    pthread_attr_destroy( &attr );\r
+    if ( result ) {\r
+      stream_.callbackInfo.isRunning = false;\r
+      errorText_ = "RtApiOss::error creating callback thread!";\r
+      goto error;\r
+    }\r
+  }\r
+\r
+  return SUCCESS;\r
+\r
+ error:\r
+  if ( handle ) {\r
+    pthread_cond_destroy( &handle->runnable );\r
+    if ( handle->id[0] ) close( handle->id[0] );\r
+    if ( handle->id[1] ) close( handle->id[1] );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  return FAILURE;\r
+}\r
+\r
+void RtApiOss :: closeStream()\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiOss::closeStream(): no open stream to close!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  stream_.callbackInfo.isRunning = false;\r
+  MUTEX_LOCK( &stream_.mutex );\r
+  if ( stream_.state == STREAM_STOPPED )\r
+    pthread_cond_signal( &handle->runnable );\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+  pthread_join( stream_.callbackInfo.thread, NULL );\r
+\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
+      ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
+    else\r
+      ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
+    stream_.state = STREAM_STOPPED;\r
+  }\r
+\r
+  if ( handle ) {\r
+    pthread_cond_destroy( &handle->runnable );\r
+    if ( handle->id[0] ) close( handle->id[0] );\r
+    if ( handle->id[1] ) close( handle->id[1] );\r
+    delete handle;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+}\r
+\r
+void RtApiOss :: startStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_RUNNING ) {\r
+    errorText_ = "RtApiOss::startStream(): the stream is already running!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  stream_.state = STREAM_RUNNING;\r
+\r
+  // No need to do anything else here ... OSS automatically starts\r
+  // when fed samples.\r
+\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  pthread_cond_signal( &handle->runnable );\r
+}\r
+\r
+void RtApiOss :: stopStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  // The state might change while waiting on a mutex.\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+    return;\r
+  }\r
+\r
+  int result = 0;\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Flush the output with zeros a few times.\r
+    char *buffer;\r
+    int samples;\r
+    RtAudioFormat format;\r
+\r
+    if ( stream_.doConvertBuffer[0] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      samples = stream_.bufferSize * stream_.nDeviceChannels[0];\r
+      format = stream_.deviceFormat[0];\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[0];\r
+      samples = stream_.bufferSize * stream_.nUserChannels[0];\r
+      format = stream_.userFormat;\r
+    }\r
+\r
+    memset( buffer, 0, samples * formatBytes(format) );\r
+    for ( unsigned int i=0; i<stream_.nBuffers+1; i++ ) {\r
+      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
+      if ( result == -1 ) {\r
+        errorText_ = "RtApiOss::stopStream: audio write error.";\r
+        error( RtAudioError::WARNING );\r
+      }\r
+    }\r
+\r
+    result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
+    if ( result == -1 ) {\r
+      errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+    handle->triggered = false;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {\r
+    result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
+    if ( result == -1 ) {\r
+      errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( result != -1 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiOss :: abortStream()\r
+{\r
+  verifyStream();\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  // The state might change while waiting on a mutex.\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+    return;\r
+  }\r
+\r
+  int result = 0;\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
+    if ( result == -1 ) {\r
+      errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+    handle->triggered = false;\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {\r
+    result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
+    if ( result == -1 ) {\r
+      errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";\r
+      errorText_ = errorStream_.str();\r
+      goto unlock;\r
+    }\r
+  }\r
+\r
+ unlock:\r
+  stream_.state = STREAM_STOPPED;\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  if ( result != -1 ) return;\r
+  error( RtAudioError::SYSTEM_ERROR );\r
+}\r
+\r
+void RtApiOss :: callbackEvent()\r
+{\r
+  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
+  if ( stream_.state == STREAM_STOPPED ) {\r
+    MUTEX_LOCK( &stream_.mutex );\r
+    pthread_cond_wait( &handle->runnable, &stream_.mutex );\r
+    if ( stream_.state != STREAM_RUNNING ) {\r
+      MUTEX_UNLOCK( &stream_.mutex );\r
+      return;\r
+    }\r
+    MUTEX_UNLOCK( &stream_.mutex );\r
+  }\r
+\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
+    error( RtAudioError::WARNING );\r
+    return;\r
+  }\r
+\r
+  // Invoke user callback to get fresh output data.\r
+  int doStopStream = 0;\r
+  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
+  double streamTime = getStreamTime();\r
+  RtAudioStreamStatus status = 0;\r
+  if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
+    status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
+    handle->xrun[0] = false;\r
+  }\r
+  if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
+    status |= RTAUDIO_INPUT_OVERFLOW;\r
+    handle->xrun[1] = false;\r
+  }\r
+  doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+                           stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );\r
+  if ( doStopStream == 2 ) {\r
+    this->abortStream();\r
+    return;\r
+  }\r
+\r
+  MUTEX_LOCK( &stream_.mutex );\r
+\r
+  // The state might change while waiting on a mutex.\r
+  if ( stream_.state == STREAM_STOPPED ) goto unlock;\r
+\r
+  int result;\r
+  char *buffer;\r
+  int samples;\r
+  RtAudioFormat format;\r
+\r
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Setup parameters and do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[0] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
+      samples = stream_.bufferSize * stream_.nDeviceChannels[0];\r
+      format = stream_.deviceFormat[0];\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[0];\r
+      samples = stream_.bufferSize * stream_.nUserChannels[0];\r
+      format = stream_.userFormat;\r
+    }\r
+\r
+    // Do byte swapping if necessary.\r
+    if ( stream_.doByteSwap[0] )\r
+      byteSwapBuffer( buffer, samples, format );\r
+\r
+    if ( stream_.mode == DUPLEX && handle->triggered == false ) {\r
+      int trig = 0;\r
+      ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );\r
+      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
+      trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT;\r
+      ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );\r
+      handle->triggered = true;\r
+    }\r
+    else\r
+      // Write samples to device.\r
+      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
+\r
+    if ( result == -1 ) {\r
+      // We'll assume this is an underrun, though there isn't a\r
+      // specific means for determining that.\r
+      handle->xrun[0] = true;\r
+      errorText_ = "RtApiOss::callbackEvent: audio write error.";\r
+      error( RtAudioError::WARNING );\r
+      // Continue on to input section.\r
+    }\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
+\r
+    // Setup parameters.\r
+    if ( stream_.doConvertBuffer[1] ) {\r
+      buffer = stream_.deviceBuffer;\r
+      samples = stream_.bufferSize * stream_.nDeviceChannels[1];\r
+      format = stream_.deviceFormat[1];\r
+    }\r
+    else {\r
+      buffer = stream_.userBuffer[1];\r
+      samples = stream_.bufferSize * stream_.nUserChannels[1];\r
+      format = stream_.userFormat;\r
+    }\r
+\r
+    // Read samples from device.\r
+    result = read( handle->id[1], buffer, samples * formatBytes(format) );\r
+\r
+    if ( result == -1 ) {\r
+      // We'll assume this is an overrun, though there isn't a\r
+      // specific means for determining that.\r
+      handle->xrun[1] = true;\r
+      errorText_ = "RtApiOss::callbackEvent: audio read error.";\r
+      error( RtAudioError::WARNING );\r
+      goto unlock;\r
+    }\r
+\r
+    // Do byte swapping if necessary.\r
+    if ( stream_.doByteSwap[1] )\r
+      byteSwapBuffer( buffer, samples, format );\r
+\r
+    // Do buffer conversion if necessary.\r
+    if ( stream_.doConvertBuffer[1] )\r
+      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
+  }\r
+\r
+ unlock:\r
+  MUTEX_UNLOCK( &stream_.mutex );\r
+\r
+  RtApi::tickStreamTime();\r
+  if ( doStopStream == 1 ) this->stopStream();\r
+}\r
+\r
+static void *ossCallbackHandler( void *ptr )\r
+{\r
+  CallbackInfo *info = (CallbackInfo *) ptr;\r
+  RtApiOss *object = (RtApiOss *) info->object;\r
+  bool *isRunning = &info->isRunning;\r
+\r
+  while ( *isRunning == true ) {\r
+    pthread_testcancel();\r
+    object->callbackEvent();\r
+  }\r
+\r
+  pthread_exit( NULL );\r
+}\r
+\r
+//******************** End of __LINUX_OSS__ *********************//\r
+#endif\r
+\r
+\r
+// *************************************************** //\r
+//\r
+// Protected common (OS-independent) RtAudio methods.\r
+//\r
+// *************************************************** //\r
+\r
+// This method can be modified to control the behavior of error\r
+// message printing.\r
+void RtApi :: error( RtAudioError::Type type )\r
+{\r
+  errorStream_.str(""); // clear the ostringstream\r
+\r
+  RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;\r
+  if ( errorCallback ) {\r
+    // abortStream() can generate new error messages. Ignore them. Just keep original one.\r
+\r
+    if ( firstErrorOccurred_ )\r
+      return;\r
+\r
+    firstErrorOccurred_ = true;\r
+    const std::string errorMessage = errorText_;\r
+\r
+    if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {\r
+      stream_.callbackInfo.isRunning = false; // exit from the thread\r
+      abortStream();\r
+    }\r
+\r
+    errorCallback( type, errorMessage );\r
+    firstErrorOccurred_ = false;\r
+    return;\r
+  }\r
+\r
+  if ( type == RtAudioError::WARNING && showWarnings_ == true )\r
+    std::cerr << '\n' << errorText_ << "\n\n";\r
+  else if ( type != RtAudioError::WARNING )\r
+    throw( RtAudioError( errorText_, type ) );\r
+}\r
+\r
+void RtApi :: verifyStream()\r
+{\r
+  if ( stream_.state == STREAM_CLOSED ) {\r
+    errorText_ = "RtApi:: a stream is not open!";\r
+    error( RtAudioError::INVALID_USE );\r
+  }\r
+}\r
+\r
+void RtApi :: clearStreamInfo()\r
+{\r
+  stream_.mode = UNINITIALIZED;\r
+  stream_.state = STREAM_CLOSED;\r
+  stream_.sampleRate = 0;\r
+  stream_.bufferSize = 0;\r
+  stream_.nBuffers = 0;\r
+  stream_.userFormat = 0;\r
+  stream_.userInterleaved = true;\r
+  stream_.streamTime = 0.0;\r
+  stream_.apiHandle = 0;\r
+  stream_.deviceBuffer = 0;\r
+  stream_.callbackInfo.callback = 0;\r
+  stream_.callbackInfo.userData = 0;\r
+  stream_.callbackInfo.isRunning = false;\r
+  stream_.callbackInfo.errorCallback = 0;\r
+  for ( int i=0; i<2; i++ ) {\r
+    stream_.device[i] = 11111;\r
+    stream_.doConvertBuffer[i] = false;\r
+    stream_.deviceInterleaved[i] = true;\r
+    stream_.doByteSwap[i] = false;\r
+    stream_.nUserChannels[i] = 0;\r
+    stream_.nDeviceChannels[i] = 0;\r
+    stream_.channelOffset[i] = 0;\r
+    stream_.deviceFormat[i] = 0;\r
+    stream_.latency[i] = 0;\r
+    stream_.userBuffer[i] = 0;\r
+    stream_.convertInfo[i].channels = 0;\r
+    stream_.convertInfo[i].inJump = 0;\r
+    stream_.convertInfo[i].outJump = 0;\r
+    stream_.convertInfo[i].inFormat = 0;\r
+    stream_.convertInfo[i].outFormat = 0;\r
+    stream_.convertInfo[i].inOffset.clear();\r
+    stream_.convertInfo[i].outOffset.clear();\r
+  }\r
+}\r
+\r
+unsigned int RtApi :: formatBytes( RtAudioFormat format )\r
+{\r
+  if ( format == RTAUDIO_SINT16 )\r
+    return 2;\r
+  else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )\r
+    return 4;\r
+  else if ( format == RTAUDIO_FLOAT64 )\r
+    return 8;\r
+  else if ( format == RTAUDIO_SINT24 )\r
+    return 3;\r
+  else if ( format == RTAUDIO_SINT8 )\r
+    return 1;\r
+\r
+  errorText_ = "RtApi::formatBytes: undefined format.";\r
+  error( RtAudioError::WARNING );\r
+\r
+  return 0;\r
+}\r
+\r
+void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel )\r
+{\r
+  if ( mode == INPUT ) { // convert device to user buffer\r
+    stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];\r
+    stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];\r
+    stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];\r
+    stream_.convertInfo[mode].outFormat = stream_.userFormat;\r
+  }\r
+  else { // convert user to device buffer\r
+    stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];\r
+    stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];\r
+    stream_.convertInfo[mode].inFormat = stream_.userFormat;\r
+    stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];\r
+  }\r
+\r
+  if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )\r
+    stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;\r
+  else\r
+    stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;\r
+\r
+  // Set up the interleave/deinterleave offsets.\r
+  if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) {\r
+    if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) ||\r
+         ( mode == INPUT && stream_.userInterleaved ) ) {\r
+      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
+        stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );\r
+        stream_.convertInfo[mode].outOffset.push_back( k );\r
+        stream_.convertInfo[mode].inJump = 1;\r
+      }\r
+    }\r
+    else {\r
+      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
+        stream_.convertInfo[mode].inOffset.push_back( k );\r
+        stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );\r
+        stream_.convertInfo[mode].outJump = 1;\r
+      }\r
+    }\r
+  }\r
+  else { // no (de)interleaving\r
+    if ( stream_.userInterleaved ) {\r
+      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
+        stream_.convertInfo[mode].inOffset.push_back( k );\r
+        stream_.convertInfo[mode].outOffset.push_back( k );\r
+      }\r
+    }\r
+    else {\r
+      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
+        stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );\r
+        stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );\r
+        stream_.convertInfo[mode].inJump = 1;\r
+        stream_.convertInfo[mode].outJump = 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  // Add channel offset.\r
+  if ( firstChannel > 0 ) {\r
+    if ( stream_.deviceInterleaved[mode] ) {\r
+      if ( mode == OUTPUT ) {\r
+        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
+          stream_.convertInfo[mode].outOffset[k] += firstChannel;\r
+      }\r
+      else {\r
+        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
+          stream_.convertInfo[mode].inOffset[k] += firstChannel;\r
+      }\r
+    }\r
+    else {\r
+      if ( mode == OUTPUT ) {\r
+        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
+          stream_.convertInfo[mode].outOffset[k] += ( firstChannel * stream_.bufferSize );\r
+      }\r
+      else {\r
+        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
+          stream_.convertInfo[mode].inOffset[k] += ( firstChannel  * stream_.bufferSize );\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )\r
+{\r
+  // This function does format conversion, input/output channel compensation, and\r
+  // data interleaving/deinterleaving.  24-bit integers are assumed to occupy\r
+  // the lower three bytes of a 32-bit integer.\r
+\r
+  // Clear our device buffer when in/out duplex device channels are different\r
+  if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&\r
+       ( stream_.nDeviceChannels[0] < stream_.nDeviceChannels[1] ) )\r
+    memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );\r
+\r
+  int j;\r
+  if (info.outFormat == RTAUDIO_FLOAT64) {\r
+    Float64 scale;\r
+    Float64 *out = (Float64 *)outBuffer;\r
+\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      signed char *in = (signed char *)inBuffer;\r
+      scale = 1.0 / 127.5;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT16) {\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      scale = 1.0 / 32767.5;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      scale = 1.0 / 8388607.5;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      scale = 1.0 / 2147483647.5;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+  else if (info.outFormat == RTAUDIO_FLOAT32) {\r
+    Float32 scale;\r
+    Float32 *out = (Float32 *)outBuffer;\r
+\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      signed char *in = (signed char *)inBuffer;\r
+      scale = (Float32) ( 1.0 / 127.5 );\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT16) {\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      scale = (Float32) ( 1.0 / 32767.5 );\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      scale = (Float32) ( 1.0 / 8388607.5 );\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      scale = (Float32) ( 1.0 / 2147483647.5 );\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] += 0.5;\r
+          out[info.outOffset[j]] *= scale;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+  else if (info.outFormat == RTAUDIO_SINT32) {\r
+    Int32 *out = (Int32 *)outBuffer;\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      signed char *in = (signed char *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] <<= 24;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT16) {\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] <<= 16;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();\r
+          out[info.outOffset[j]] <<= 8;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+  else if (info.outFormat == RTAUDIO_SINT24) {\r
+    Int24 *out = (Int24 *)outBuffer;\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      signed char *in = (signed char *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);\r
+          //out[info.outOffset[j]] <<= 16;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT16) {\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);\r
+          //out[info.outOffset[j]] <<= 8;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);\r
+          //out[info.outOffset[j]] >>= 8;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+  else if (info.outFormat == RTAUDIO_SINT16) {\r
+    Int16 *out = (Int16 *)outBuffer;\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      signed char *in = (signed char *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];\r
+          out[info.outOffset[j]] <<= 8;\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT16) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+  else if (info.outFormat == RTAUDIO_SINT8) {\r
+    signed char *out = (signed char *)outBuffer;\r
+    if (info.inFormat == RTAUDIO_SINT8) {\r
+      // Channel compensation and/or (de)interleaving only.\r
+      signed char *in = (signed char *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = in[info.inOffset[j]];\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    if (info.inFormat == RTAUDIO_SINT16) {\r
+      Int16 *in = (Int16 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT24) {\r
+      Int24 *in = (Int24 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_SINT32) {\r
+      Int32 *in = (Int32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
+      Float32 *in = (Float32 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
+      Float64 *in = (Float64 *)inBuffer;\r
+      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
+        for (j=0; j<info.channels; j++) {\r
+          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);\r
+        }\r
+        in += info.inJump;\r
+        out += info.outJump;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+//static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }\r
+//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }\r
+//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }\r
+\r
+void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )\r
+{\r
+  register char val;\r
+  register char *ptr;\r
+\r
+  ptr = buffer;\r
+  if ( format == RTAUDIO_SINT16 ) {\r
+    for ( unsigned int i=0; i<samples; i++ ) {\r
+      // Swap 1st and 2nd bytes.\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+1);\r
+      *(ptr+1) = val;\r
+\r
+      // Increment 2 bytes.\r
+      ptr += 2;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_SINT32 ||\r
+            format == RTAUDIO_FLOAT32 ) {\r
+    for ( unsigned int i=0; i<samples; i++ ) {\r
+      // Swap 1st and 4th bytes.\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+3);\r
+      *(ptr+3) = val;\r
+\r
+      // Swap 2nd and 3rd bytes.\r
+      ptr += 1;\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+1);\r
+      *(ptr+1) = val;\r
+\r
+      // Increment 3 more bytes.\r
+      ptr += 3;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_SINT24 ) {\r
+    for ( unsigned int i=0; i<samples; i++ ) {\r
+      // Swap 1st and 3rd bytes.\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+2);\r
+      *(ptr+2) = val;\r
+\r
+      // Increment 2 more bytes.\r
+      ptr += 2;\r
+    }\r
+  }\r
+  else if ( format == RTAUDIO_FLOAT64 ) {\r
+    for ( unsigned int i=0; i<samples; i++ ) {\r
+      // Swap 1st and 8th bytes\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+7);\r
+      *(ptr+7) = val;\r
+\r
+      // Swap 2nd and 7th bytes\r
+      ptr += 1;\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+5);\r
+      *(ptr+5) = val;\r
+\r
+      // Swap 3rd and 6th bytes\r
+      ptr += 1;\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+3);\r
+      *(ptr+3) = val;\r
+\r
+      // Swap 4th and 5th bytes\r
+      ptr += 1;\r
+      val = *(ptr);\r
+      *(ptr) = *(ptr+1);\r
+      *(ptr+1) = val;\r
+\r
+      // Increment 5 more bytes.\r
+      ptr += 5;\r
+    }\r
+  }\r
+}\r
+\r
+  // Indentation settings for Vim and Emacs\r
+  //\r
+  // Local Variables:\r
+  // c-basic-offset: 2\r
+  // indent-tabs-mode: nil\r
+  // End:\r
+  //\r
+  // vim: et sts=2 sw=2\r
+\r
diff --git a/src/deps/rtaudio-mod/RtAudio.h b/src/deps/rtaudio-mod/RtAudio.h
new file mode 100644 (file)
index 0000000..a3534ad
--- /dev/null
@@ -0,0 +1,1177 @@
+/************************************************************************/
+/*! \class RtAudio
+    \brief Realtime audio i/o C++ classes.
+
+    RtAudio provides a common API (Application Programming Interface)
+    for realtime audio input/output across Linux (native ALSA, Jack,
+    and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
+    (DirectSound, ASIO and WASAPI) operating systems.
+
+    RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
+
+    RtAudio: realtime audio i/o C++ classes
+    Copyright (c) 2001-2014 Gary P. Scavone
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation files
+    (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software,
+    and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    Any person wishing to distribute modifications to the Software is
+    asked to send the modifications to the original developer so that
+    they can be incorporated into the canonical version.  This is,
+    however, not a binding provision of this license.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+/************************************************************************/
+
+/*!
+  \file RtAudio.h
+ */
+
+#ifndef __RTAUDIO_H
+#define __RTAUDIO_H
+
+#define RTAUDIO_VERSION "4.1.1"
+
+#include <string>
+#include <vector>
+
+/* --- Monocasual hack ---------------------------------------------- */
+#if defined(__linux__)
+#include <jack/jack.h>
+#endif
+/* ------------------------------------------------------------------ */
+
+#include <exception>
+#include <iostream>
+
+/*! \typedef typedef unsigned long RtAudioFormat;
+    \brief RtAudio data format type.
+
+    Support for signed integers and floats.  Audio data fed to/from an
+    RtAudio stream is assumed to ALWAYS be in host byte order.  The
+    internal routines will automatically take care of any necessary
+    byte-swapping between the host format and the soundcard.  Thus,
+    endian-ness is not a concern in the following format definitions.
+
+    - \e RTAUDIO_SINT8:   8-bit signed integer.
+    - \e RTAUDIO_SINT16:  16-bit signed integer.
+    - \e RTAUDIO_SINT24:  24-bit signed integer.
+    - \e RTAUDIO_SINT32:  32-bit signed integer.
+    - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0.
+    - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
+*/
+typedef unsigned long RtAudioFormat;
+static const RtAudioFormat RTAUDIO_SINT8 = 0x1;    // 8-bit signed integer.
+static const RtAudioFormat RTAUDIO_SINT16 = 0x2;   // 16-bit signed integer.
+static const RtAudioFormat RTAUDIO_SINT24 = 0x4;   // 24-bit signed integer.
+static const RtAudioFormat RTAUDIO_SINT32 = 0x8;   // 32-bit signed integer.
+static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0.
+static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0.
+
+/*! \typedef typedef unsigned long RtAudioStreamFlags;
+    \brief RtAudio stream option flags.
+
+    The following flags can be OR'ed together to allow a client to
+    make changes to the default stream behavior:
+
+    - \e RTAUDIO_NONINTERLEAVED:   Use non-interleaved buffers (default = interleaved).
+    - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
+    - \e RTAUDIO_HOG_DEVICE:       Attempt grab device for exclusive use.
+    - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
+
+    By default, RtAudio streams pass and receive audio data from the
+    client in an interleaved format.  By passing the
+    RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio
+    data will instead be presented in non-interleaved buffers.  In
+    this case, each buffer argument in the RtAudioCallback function
+    will point to a single array of data, with \c nFrames samples for
+    each channel concatenated back-to-back.  For example, the first
+    sample of data for the second channel would be located at index \c
+    nFrames (assuming the \c buffer pointer was recast to the correct
+    data type for the stream).
+
+    Certain audio APIs offer a number of parameters that influence the
+    I/O latency of a stream.  By default, RtAudio will attempt to set
+    these parameters internally for robust (glitch-free) performance
+    (though some APIs, like Windows Direct Sound, make this difficult).
+    By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
+    function, internal stream settings will be influenced in an attempt
+    to minimize stream latency, though possibly at the expense of stream
+    performance.
+
+    If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to
+    open the input and/or output stream device(s) for exclusive use.
+    Note that this is not possible with all supported audio APIs.
+
+    If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 
+    to select realtime scheduling (round-robin) for the callback thread.
+
+    If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
+    open the "default" PCM device when using the ALSA API. Note that this
+    will override any specified input or output device id.
+*/
+typedef unsigned int RtAudioStreamFlags;
+static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1;    // Use non-interleaved buffers (default = interleaved).
+static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2;  // Attempt to set stream parameters for lowest possible latency.
+static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4;        // Attempt grab device and prevent use by others.
+static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread.
+static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only).
+
+/*! \typedef typedef unsigned long RtAudioStreamStatus;
+    \brief RtAudio stream status (over- or underflow) flags.
+
+    Notification of a stream over- or underflow is indicated by a
+    non-zero stream \c status argument in the RtAudioCallback function.
+    The stream status can be one of the following two options,
+    depending on whether the stream is open for output and/or input:
+
+    - \e RTAUDIO_INPUT_OVERFLOW:   Input data was discarded because of an overflow condition at the driver.
+    - \e RTAUDIO_OUTPUT_UNDERFLOW: The output buffer ran low, likely producing a break in the output sound.
+*/
+typedef unsigned int RtAudioStreamStatus;
+static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1;    // Input data was discarded because of an overflow condition at the driver.
+static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2;  // The output buffer ran low, likely causing a gap in the output sound.
+
+//! RtAudio callback function prototype.
+/*!
+   All RtAudio clients must create a function of type RtAudioCallback
+   to read and/or write data from/to the audio stream.  When the
+   underlying audio system is ready for new input or output data, this
+   function will be invoked.
+
+   \param outputBuffer For output (or duplex) streams, the client
+          should write \c nFrames of audio sample frames into this
+          buffer.  This argument should be recast to the datatype
+          specified when the stream was opened.  For input-only
+          streams, this argument will be NULL.
+
+   \param inputBuffer For input (or duplex) streams, this buffer will
+          hold \c nFrames of input audio sample frames.  This
+          argument should be recast to the datatype specified when the
+          stream was opened.  For output-only streams, this argument
+          will be NULL.
+
+   \param nFrames The number of sample frames of input or output
+          data in the buffers.  The actual buffer size in bytes is
+          dependent on the data type and number of channels in use.
+
+   \param streamTime The number of seconds that have elapsed since the
+          stream was started.
+
+   \param status If non-zero, this argument indicates a data overflow
+          or underflow condition for the stream.  The particular
+          condition can be determined by comparison with the
+          RtAudioStreamStatus flags.
+
+   \param userData A pointer to optional data provided by the client
+          when opening the stream (default = NULL).
+
+   To continue normal stream operation, the RtAudioCallback function
+   should return a value of zero.  To stop the stream and drain the
+   output buffer, the function should return a value of one.  To abort
+   the stream immediately, the client should return a value of two.
+ */
+typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
+                                unsigned int nFrames,
+                                double streamTime,
+                                RtAudioStreamStatus status,
+                                void *userData );
+
+/************************************************************************/
+/*! \class RtAudioError
+    \brief Exception handling class for RtAudio.
+
+    The RtAudioError class is quite simple but it does allow errors to be
+    "caught" by RtAudioError::Type. See the RtAudio documentation to know
+    which methods can throw an RtAudioError.
+*/
+/************************************************************************/
+
+class RtAudioError : public std::exception
+{
+ public:
+  //! Defined RtAudioError types.
+  enum Type {
+    WARNING,           /*!< A non-critical error. */
+    DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
+    UNSPECIFIED,       /*!< The default, unspecified error type. */
+    NO_DEVICES_FOUND,  /*!< No devices found on system. */
+    INVALID_DEVICE,    /*!< An invalid device ID was specified. */
+    MEMORY_ERROR,      /*!< An error occured during memory allocation. */
+    INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
+    INVALID_USE,       /*!< The function was called incorrectly. */
+    DRIVER_ERROR,      /*!< A system driver error occured. */
+    SYSTEM_ERROR,      /*!< A system error occured. */
+    THREAD_ERROR       /*!< A thread error occured. */
+  };
+
+  //! The constructor.
+  RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
+  //! The destructor.
+  virtual ~RtAudioError( void ) throw() {}
+
+  //! Prints thrown error message to stderr.
+  virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
+
+  //! Returns the thrown error message type.
+  virtual const Type& getType(void) const throw() { return type_; }
+
+  //! Returns the thrown error message string.
+  virtual const std::string& getMessage(void) const throw() { return message_; }
+
+  //! Returns the thrown error message as a c-style string.
+  virtual const char* what( void ) const throw() { return message_.c_str(); }
+
+ protected:
+  std::string message_;
+  Type type_;
+};
+
+//! RtAudio error callback function prototype.
+/*!
+    \param type Type of error.
+    \param errorText Error description.
+ */
+typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText );
+
+// **************************************************************** //
+//
+// RtAudio class declaration.
+//
+// RtAudio is a "controller" used to select an available audio i/o
+// interface.  It presents a common API for the user to call but all
+// functionality is implemented by the class RtApi and its
+// subclasses.  RtAudio creates an instance of an RtApi subclass
+// based on the user's API choice.  If no choice is made, RtAudio
+// attempts to make a "logical" API selection.
+//
+// **************************************************************** //
+
+class RtApi;
+
+class RtAudio
+{
+ public:
+
+  //! Audio API specifier arguments.
+  enum Api {
+    UNSPECIFIED,    /*!< Search for a working compiled API. */
+    LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
+    LINUX_PULSE,    /*!< The Linux PulseAudio API. */
+    LINUX_OSS,      /*!< The Linux Open Sound System API. */
+    UNIX_JACK,      /*!< The Jack Low-Latency Audio Server API. */
+    MACOSX_CORE,    /*!< Macintosh OS-X Core Audio API. */
+    WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
+    WINDOWS_ASIO,   /*!< The Steinberg Audio Stream I/O API. */
+    WINDOWS_DS,     /*!< The Microsoft Direct Sound API. */
+    RTAUDIO_DUMMY   /*!< A compilable but non-functional API. */
+  };
+
+  //! The public device information structure for returning queried values.
+  struct DeviceInfo {
+    bool probed;                  /*!< true if the device capabilities were successfully probed. */
+    std::string name;             /*!< Character string device identifier. */
+    unsigned int outputChannels;  /*!< Maximum output channels supported by device. */
+    unsigned int inputChannels;   /*!< Maximum input channels supported by device. */
+    unsigned int duplexChannels;  /*!< Maximum simultaneous input/output channels supported by device. */
+    bool isDefaultOutput;         /*!< true if this is the default output device. */
+    bool isDefaultInput;          /*!< true if this is the default input device. */
+    std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
+    RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
+
+    // Default constructor.
+    DeviceInfo()
+      :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
+       isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
+  };
+
+  //! The structure for specifying input or ouput stream parameters.
+  struct StreamParameters {
+    unsigned int deviceId;     /*!< Device index (0 to getDeviceCount() - 1). */
+    unsigned int nChannels;    /*!< Number of channels. */
+    unsigned int firstChannel; /*!< First channel index on device (default = 0). */
+
+    // Default constructor.
+    StreamParameters()
+      : deviceId(0), nChannels(0), firstChannel(0) {}
+  };
+
+  //! The structure for specifying stream options.
+  /*!
+    The following flags can be OR'ed together to allow a client to
+    make changes to the default stream behavior:
+
+    - \e RTAUDIO_NONINTERLEAVED:    Use non-interleaved buffers (default = interleaved).
+    - \e RTAUDIO_MINIMIZE_LATENCY:  Attempt to set stream parameters for lowest possible latency.
+    - \e RTAUDIO_HOG_DEVICE:        Attempt grab device for exclusive use.
+    - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread.
+    - \e RTAUDIO_ALSA_USE_DEFAULT:  Use the "default" PCM device (ALSA only).
+
+    By default, RtAudio streams pass and receive audio data from the
+    client in an interleaved format.  By passing the
+    RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio
+    data will instead be presented in non-interleaved buffers.  In
+    this case, each buffer argument in the RtAudioCallback function
+    will point to a single array of data, with \c nFrames samples for
+    each channel concatenated back-to-back.  For example, the first
+    sample of data for the second channel would be located at index \c
+    nFrames (assuming the \c buffer pointer was recast to the correct
+    data type for the stream).
+
+    Certain audio APIs offer a number of parameters that influence the
+    I/O latency of a stream.  By default, RtAudio will attempt to set
+    these parameters internally for robust (glitch-free) performance
+    (though some APIs, like Windows Direct Sound, make this difficult).
+    By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
+    function, internal stream settings will be influenced in an attempt
+    to minimize stream latency, though possibly at the expense of stream
+    performance.
+
+    If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to
+    open the input and/or output stream device(s) for exclusive use.
+    Note that this is not possible with all supported audio APIs.
+
+    If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 
+    to select realtime scheduling (round-robin) for the callback thread.
+    The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME
+    flag is set. It defines the thread's realtime priority.
+
+    If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
+    open the "default" PCM device when using the ALSA API. Note that this
+    will override any specified input or output device id.
+
+    The \c numberOfBuffers parameter can be used to control stream
+    latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs
+    only.  A value of two is usually the smallest allowed.  Larger
+    numbers can potentially result in more robust stream performance,
+    though likely at the cost of stream latency.  The value set by the
+    user is replaced during execution of the RtAudio::openStream()
+    function by the value actually used by the system.
+
+    The \c streamName parameter can be used to set the client name
+    when using the Jack API.  By default, the client name is set to
+    RtApiJack.  However, if you wish to create multiple instances of
+    RtAudio with Jack, each instance must have a unique client name.
+  */
+  struct StreamOptions {
+    RtAudioStreamFlags flags;      /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */
+    unsigned int numberOfBuffers;  /*!< Number of stream buffers. */
+    std::string streamName;        /*!< A stream name (currently used only in Jack). */
+    int priority;                  /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */
+
+    // Default constructor.
+    StreamOptions()
+    : flags(0), numberOfBuffers(0), priority(0) {}
+  };
+
+  //! A static function to determine the current RtAudio version.
+  static std::string getVersion( void ) throw();
+
+  //! A static function to determine the available compiled audio APIs.
+  /*!
+    The values returned in the std::vector can be compared against
+    the enumerated list values.  Note that there can be more than one
+    API compiled for certain operating systems.
+  */
+  static void getCompiledApi( std::vector<RtAudio::Api> &apis ) throw();
+
+  //! The class constructor.
+  /*!
+    The constructor performs minor initialization tasks.  An exception
+    can be thrown if no API support is compiled.
+
+    If no API argument is specified and multiple API support has been
+    compiled, the default order of use is JACK, ALSA, OSS (Linux
+    systems) and ASIO, DS (Windows systems).
+  */
+  RtAudio( RtAudio::Api api=UNSPECIFIED );
+
+  //! The destructor.
+  /*!
+    If a stream is running or open, it will be stopped and closed
+    automatically.
+  */
+  ~RtAudio() throw();
+
+  //! Returns the audio API specifier for the current instance of RtAudio.
+  RtAudio::Api getCurrentApi( void ) throw();
+
+  //! A public function that queries for the number of audio devices available.
+  /*!
+    This function performs a system query of available devices each time it
+    is called, thus supporting devices connected \e after instantiation. If
+    a system error occurs during processing, a warning will be issued. 
+  */
+  unsigned int getDeviceCount( void ) throw();
+
+  //! Return an RtAudio::DeviceInfo structure for a specified device number.
+  /*!
+
+    Any device integer between 0 and getDeviceCount() - 1 is valid.
+    If an invalid argument is provided, an RtAudioError (type = INVALID_USE)
+    will be thrown.  If a device is busy or otherwise unavailable, the
+    structure member "probed" will have a value of "false" and all
+    other members are undefined.  If the specified device is the
+    current default input or output device, the corresponding
+    "isDefault" member will have a value of "true".
+  */
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+
+  //! A function that returns the index of the default output device.
+  /*!
+    If the underlying audio API does not provide a "default
+    device", or if no devices are available, the return value will be
+    0.  Note that this is a valid device identifier and it is the
+    client's responsibility to verify that a device is available
+    before attempting to open a stream.
+  */
+  unsigned int getDefaultOutputDevice( void ) throw();
+
+  //! A function that returns the index of the default input device.
+  /*!
+    If the underlying audio API does not provide a "default
+    device", or if no devices are available, the return value will be
+    0.  Note that this is a valid device identifier and it is the
+    client's responsibility to verify that a device is available
+    before attempting to open a stream.
+  */
+  unsigned int getDefaultInputDevice( void ) throw();
+
+  //! A public function for opening a stream with the specified parameters.
+  /*!
+    An RtAudioError (type = SYSTEM_ERROR) is thrown if a stream cannot be
+    opened with the specified parameters or an error occurs during
+    processing.  An RtAudioError (type = INVALID_USE) is thrown if any
+    invalid device ID or channel number parameters are specified.
+
+    \param outputParameters Specifies output stream parameters to use
+           when opening a stream, including a device ID, number of channels,
+           and starting channel number.  For input-only streams, this
+           argument should be NULL.  The device ID is an index value between
+           0 and getDeviceCount() - 1.
+    \param inputParameters Specifies input stream parameters to use
+           when opening a stream, including a device ID, number of channels,
+           and starting channel number.  For output-only streams, this
+           argument should be NULL.  The device ID is an index value between
+           0 and getDeviceCount() - 1.
+    \param format An RtAudioFormat specifying the desired sample data format.
+    \param sampleRate The desired sample rate (sample frames per second).
+    \param *bufferFrames A pointer to a value indicating the desired
+           internal buffer size in sample frames.  The actual value
+           used by the device is returned via the same pointer.  A
+           value of zero can be specified, in which case the lowest
+           allowable value is determined.
+    \param callback A client-defined function that will be invoked
+           when input data is available and/or output data is needed.
+    \param userData An optional pointer to data that can be accessed
+           from within the callback function.
+    \param options An optional pointer to a structure containing various
+           global stream options, including a list of OR'ed RtAudioStreamFlags
+           and a suggested number of stream buffers that can be used to 
+           control stream latency.  More buffers typically result in more
+           robust performance, though at a cost of greater latency.  If a
+           value of zero is specified, a system-specific median value is
+           chosen.  If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the
+           lowest allowable value is used.  The actual value used is
+           returned via the structure argument.  The parameter is API dependent.
+    \param errorCallback A client-defined function that will be invoked
+           when an error has occured.
+  */
+  void openStream( RtAudio::StreamParameters *outputParameters,
+                   RtAudio::StreamParameters *inputParameters,
+                   RtAudioFormat format, unsigned int sampleRate,
+                   unsigned int *bufferFrames, RtAudioCallback callback,
+                   void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL );
+
+  //! A function that closes a stream and frees any associated stream memory.
+  /*!
+    If a stream is not open, this function issues a warning and
+    returns (no exception is thrown).
+  */
+  void closeStream( void ) throw();
+
+  //! A function that starts a stream.
+  /*!
+    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
+    stream is not open.  A warning is issued if the stream is already
+    running.
+  */
+  void startStream( void );
+
+  //! Stop a stream, allowing any samples remaining in the output queue to be played.
+  /*!
+    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
+    stream is not open.  A warning is issued if the stream is already
+    stopped.
+  */
+  void stopStream( void );
+
+  //! Stop a stream, discarding any samples remaining in the input/output queue.
+  /*!
+    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
+    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
+    stream is not open.  A warning is issued if the stream is already
+    stopped.
+  */
+  void abortStream( void );
+
+  //! Returns true if a stream is open and false if not.
+  bool isStreamOpen( void ) const throw();
+
+  //! Returns true if the stream is running and false if it is stopped or not open.
+  bool isStreamRunning( void ) const throw();
+
+  //! Returns the number of elapsed seconds since the stream was started.
+  /*!
+    If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
+  */
+  double getStreamTime( void );
+
+  //! Set the stream time to a time in seconds greater than or equal to 0.0.
+  /*!
+    If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
+  */
+  void setStreamTime( double time );
+
+  //! Returns the internal stream latency in sample frames.
+  /*!
+    The stream latency refers to delay in audio input and/or output
+    caused by internal buffering by the audio system and/or hardware.
+    For duplex streams, the returned value will represent the sum of
+    the input and output latencies.  If a stream is not open, an
+    RtAudioError (type = INVALID_USE) will be thrown.  If the API does not
+    report latency, the return value will be zero.
+  */
+  long getStreamLatency( void );
+
+ //! Returns actual sample rate in use by the stream.
+ /*!
+   On some systems, the sample rate used may be slightly different
+   than that specified in the stream parameters.  If a stream is not
+   open, an RtAudioError (type = INVALID_USE) will be thrown.
+ */
+  unsigned int getStreamSampleRate( void );
+
+  //! Specify whether warning messages should be printed to stderr.
+  void showWarnings( bool value = true ) throw();
+  
+/* --- Monocasual hack ---------------------------------------------- */
+       //protected:
+/* ------------------------------------------------------------------ */
+
+  void openRtApi( RtAudio::Api api );
+  RtApi *rtapi_;
+};
+
+// Operating system dependent thread functionality.
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
+
+  #ifndef NOMINMAX
+    #define NOMINMAX
+  #endif
+  #include <windows.h>
+  #include <process.h>
+
+  typedef uintptr_t ThreadHandle;
+  typedef CRITICAL_SECTION StreamMutex;
+
+#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
+  // Using pthread library for various flavors of unix.
+  #include <pthread.h>
+
+  typedef pthread_t ThreadHandle;
+  typedef pthread_mutex_t StreamMutex;
+
+#else // Setup for "dummy" behavior
+
+  #define __RTAUDIO_DUMMY__
+  typedef int ThreadHandle;
+  typedef int StreamMutex;
+
+#endif
+
+// This global structure type is used to pass callback information
+// between the private RtAudio stream structure and global callback
+// handling functions.
+struct CallbackInfo {
+  void *object;    // Used as a "this" pointer.
+  ThreadHandle thread;
+  void *callback;
+  void *userData;
+  void *errorCallback;
+  void *apiInfo;   // void pointer for API specific callback information
+  bool isRunning;
+  bool doRealtime;
+  int priority;
+
+  // Default constructor.
+  CallbackInfo()
+  :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {}
+};
+
+// **************************************************************** //
+//
+// RtApi class declaration.
+//
+// Subclasses of RtApi contain all API- and OS-specific code necessary
+// to fully implement the RtAudio API.
+//
+// Note that RtApi is an abstract base class and cannot be
+// explicitly instantiated.  The class RtAudio will create an
+// instance of an RtApi subclass (RtApiOss, RtApiAlsa,
+// RtApiJack, RtApiCore, RtApiDs, or RtApiAsio).
+//
+// **************************************************************** //
+
+#pragma pack(push, 1)
+class S24 {
+
+ protected:
+  unsigned char c3[3];
+
+ public:
+  S24() {}
+
+  S24& operator = ( const int& i ) {
+    c3[0] = (i & 0x000000ff);
+    c3[1] = (i & 0x0000ff00) >> 8;
+    c3[2] = (i & 0x00ff0000) >> 16;
+    return *this;
+  }
+
+  S24( const S24& v ) { *this = v; }
+  S24( const double& d ) { *this = (int) d; }
+  S24( const float& f ) { *this = (int) f; }
+  S24( const signed short& s ) { *this = (int) s; }
+  S24( const char& c ) { *this = (int) c; }
+
+  int asInt() {
+    int i = c3[0] | (c3[1] << 8) | (c3[2] << 16);
+    if (i & 0x800000) i |= ~0xffffff;
+    return i;
+  }
+};
+#pragma pack(pop)
+
+#if defined( HAVE_GETTIMEOFDAY )
+  #include <sys/time.h>
+#endif
+
+#include <sstream>
+
+class RtApi
+{
+public:
+
+/* --- Monocasual hack ---------------------------------------------- */
+#ifdef __linux__
+       void *__HACK__getJackClient();
+#endif
+/* ------------------------------------------------------------------ */
+
+  RtApi();
+  virtual ~RtApi();
+  virtual RtAudio::Api getCurrentApi( void ) = 0;
+  virtual unsigned int getDeviceCount( void ) = 0;
+  virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0;
+  virtual unsigned int getDefaultInputDevice( void );
+  virtual unsigned int getDefaultOutputDevice( void );
+  void openStream( RtAudio::StreamParameters *outputParameters,
+                   RtAudio::StreamParameters *inputParameters,
+                   RtAudioFormat format, unsigned int sampleRate,
+                   unsigned int *bufferFrames, RtAudioCallback callback,
+                   void *userData, RtAudio::StreamOptions *options,
+                   RtAudioErrorCallback errorCallback );
+  virtual void closeStream( void );
+  virtual void startStream( void ) = 0;
+  virtual void stopStream( void ) = 0;
+  virtual void abortStream( void ) = 0;
+  long getStreamLatency( void );
+  unsigned int getStreamSampleRate( void );
+  virtual double getStreamTime( void );
+  virtual void setStreamTime( double time );
+  bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }
+  bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }
+  void showWarnings( bool value ) { showWarnings_ = value; }
+
+
+protected:
+
+  static const unsigned int MAX_SAMPLE_RATES;
+  static const unsigned int SAMPLE_RATES[];
+
+  enum { FAILURE, SUCCESS };
+
+  enum StreamState {
+    STREAM_STOPPED,
+    STREAM_STOPPING,
+    STREAM_RUNNING,
+    STREAM_CLOSED = -50
+  };
+
+  enum StreamMode {
+    OUTPUT,
+    INPUT,
+    DUPLEX,
+    UNINITIALIZED = -75
+  };
+
+  // A protected structure used for buffer conversion.
+  struct ConvertInfo {
+    int channels;
+    int inJump, outJump;
+    RtAudioFormat inFormat, outFormat;
+    std::vector<int> inOffset;
+    std::vector<int> outOffset;
+  };
+
+  // A protected structure for audio streams.
+  struct RtApiStream {
+    unsigned int device[2];    // Playback and record, respectively.
+    void *apiHandle;           // void pointer for API specific stream handle information
+    StreamMode mode;           // OUTPUT, INPUT, or DUPLEX.
+    StreamState state;         // STOPPED, RUNNING, or CLOSED
+    char *userBuffer[2];       // Playback and record, respectively.
+    char *deviceBuffer;
+    bool doConvertBuffer[2];   // Playback and record, respectively.
+    bool userInterleaved;
+    bool deviceInterleaved[2]; // Playback and record, respectively.
+    bool doByteSwap[2];        // Playback and record, respectively.
+    unsigned int sampleRate;
+    unsigned int bufferSize;
+    unsigned int nBuffers;
+    unsigned int nUserChannels[2];    // Playback and record, respectively.
+    unsigned int nDeviceChannels[2];  // Playback and record channels, respectively.
+    unsigned int channelOffset[2];    // Playback and record, respectively.
+    unsigned long latency[2];         // Playback and record, respectively.
+    RtAudioFormat userFormat;
+    RtAudioFormat deviceFormat[2];    // Playback and record, respectively.
+    StreamMutex mutex;
+    CallbackInfo callbackInfo;
+    ConvertInfo convertInfo[2];
+    double streamTime;         // Number of elapsed seconds since the stream started.
+
+#if defined(HAVE_GETTIMEOFDAY)
+    struct timeval lastTickTimestamp;
+#endif
+
+    RtApiStream()
+      :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; }
+  };
+
+  typedef S24 Int24;
+  typedef signed short Int16;
+  typedef signed int Int32;
+  typedef float Float32;
+  typedef double Float64;
+
+  std::ostringstream errorStream_;
+  std::string errorText_;
+  bool showWarnings_;
+  RtApiStream stream_;
+  bool firstErrorOccurred_;
+
+  /*!
+    Protected, api-specific method that attempts to open a device
+    with the given parameters.  This function MUST be implemented by
+    all subclasses.  If an error is encountered during the probe, a
+    "warning" message is reported and FAILURE is returned. A
+    successful probe is indicated by a return value of SUCCESS.
+  */
+  virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                                unsigned int firstChannel, unsigned int sampleRate,
+                                RtAudioFormat format, unsigned int *bufferSize,
+                                RtAudio::StreamOptions *options );
+
+  //! A protected function used to increment the stream time.
+  void tickStreamTime( void );
+
+  //! Protected common method to clear an RtApiStream structure.
+  void clearStreamInfo();
+
+  /*!
+    Protected common method that throws an RtAudioError (type =
+    INVALID_USE) if a stream is not open.
+  */
+  void verifyStream( void );
+
+  //! Protected common error method to allow global control over error handling.
+  void error( RtAudioError::Type type );
+
+  /*!
+    Protected method used to perform format, channel number, and/or interleaving
+    conversions between the user and device buffers.
+  */
+  void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info );
+
+  //! Protected common method used to perform byte-swapping on buffers.
+  void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format );
+
+  //! Protected common method that returns the number of bytes for a given format.
+  unsigned int formatBytes( RtAudioFormat format );
+
+  //! Protected common method that sets up the parameters for buffer conversion.
+  void setConvertInfo( StreamMode mode, unsigned int firstChannel );
+};
+
+// **************************************************************** //
+//
+// Inline RtAudio definitions.
+//
+// **************************************************************** //
+
+inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
+inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); }
+inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
+inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); }
+inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); }
+inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); }
+inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
+inline void RtAudio :: stopStream( void )  { return rtapi_->stopStream(); }
+inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
+inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
+inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
+inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
+inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
+inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
+inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); }
+inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
+
+// RtApi Subclass prototypes.
+
+#if defined(__MACOSX_CORE__)
+
+#include <CoreAudio/AudioHardware.h>
+
+class RtApiCore: public RtApi
+{
+public:
+
+  RtApiCore();
+  ~RtApiCore();
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  unsigned int getDefaultOutputDevice( void );
+  unsigned int getDefaultInputDevice( void );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+  long getStreamLatency( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  bool callbackEvent( AudioDeviceID deviceId,
+                      const AudioBufferList *inBufferList,
+                      const AudioBufferList *outBufferList );
+
+  private:
+
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+  static const char* getErrorCode( OSStatus code );
+};
+
+#endif
+
+#if defined(__UNIX_JACK__)
+
+class RtApiJack: public RtApi
+{
+public:
+
+  RtApiJack();
+  ~RtApiJack();
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+  long getStreamLatency( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  bool callbackEvent( unsigned long nframes );
+
+  private:
+
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__WINDOWS_ASIO__)
+
+class RtApiAsio: public RtApi
+{
+public:
+
+  RtApiAsio();
+  ~RtApiAsio();
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+  long getStreamLatency( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  bool callbackEvent( long bufferIndex );
+
+  private:
+
+  std::vector<RtAudio::DeviceInfo> devices_;
+  void saveDeviceInfo( void );
+  bool coInitialized_;
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__WINDOWS_DS__)
+
+class RtApiDs: public RtApi
+{
+public:
+
+  RtApiDs();
+  ~RtApiDs();
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
+  unsigned int getDeviceCount( void );
+  unsigned int getDefaultOutputDevice( void );
+  unsigned int getDefaultInputDevice( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+  long getStreamLatency( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( void );
+
+  private:
+
+  bool coInitialized_;
+  bool buffersRolling;
+  long duplexPrerollBytes;
+  std::vector<struct DsDevice> dsDevices;
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__WINDOWS_WASAPI__)
+
+struct IMMDeviceEnumerator;
+
+class RtApiWasapi : public RtApi
+{
+public:
+  RtApiWasapi();
+  ~RtApiWasapi();
+
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  unsigned int getDefaultOutputDevice( void );
+  unsigned int getDefaultInputDevice( void );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+
+private:
+  bool coInitialized_;
+  IMMDeviceEnumerator* deviceEnumerator_;
+
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int* bufferSize,
+                        RtAudio::StreamOptions* options );
+
+  static DWORD WINAPI runWasapiThread( void* wasapiPtr );
+  static DWORD WINAPI stopWasapiThread( void* wasapiPtr );
+  static DWORD WINAPI abortWasapiThread( void* wasapiPtr );
+  void wasapiThread();
+};
+
+#endif
+
+#if defined(__LINUX_ALSA__)
+
+class RtApiAlsa: public RtApi
+{
+public:
+
+  RtApiAlsa();
+  ~RtApiAlsa();
+  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( void );
+
+  private:
+
+  std::vector<RtAudio::DeviceInfo> devices_;
+  void saveDeviceInfo( void );
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__LINUX_PULSE__)
+
+class RtApiPulse: public RtApi
+{
+public:
+  ~RtApiPulse();
+  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( void );
+
+  private:
+
+  std::vector<RtAudio::DeviceInfo> devices_;
+  void saveDeviceInfo( void );
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__LINUX_OSS__)
+
+class RtApiOss: public RtApi
+{
+public:
+
+  RtApiOss();
+  ~RtApiOss();
+  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
+  unsigned int getDeviceCount( void );
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
+  void closeStream( void );
+  void startStream( void );
+  void stopStream( void );
+  void abortStream( void );
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( void );
+
+  private:
+
+  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
+                        unsigned int firstChannel, unsigned int sampleRate,
+                        RtAudioFormat format, unsigned int *bufferSize,
+                        RtAudio::StreamOptions *options );
+};
+
+#endif
+
+#if defined(__RTAUDIO_DUMMY__)
+
+class RtApiDummy: public RtApi
+{
+public:
+
+  RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); }
+  RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }
+  unsigned int getDeviceCount( void ) { return 0; }
+  RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; }
+  void closeStream( void ) {}
+  void startStream( void ) {}
+  void stopStream( void ) {}
+  void abortStream( void ) {}
+
+  private:
+
+  bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, 
+                        unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
+                        RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
+                        RtAudio::StreamOptions * /*options*/ ) { return false; }
+};
+
+#endif
+
+#endif
+
+// Indentation settings for Vim and Emacs
+//
+// Local Variables:
+// c-basic-offset: 2
+// indent-tabs-mode: nil
+// End:
+//
+// vim: et sts=2 sw=2
diff --git a/src/deps/rtaudio-mod/config/config.guess b/src/deps/rtaudio-mod/config/config.guess
new file mode 100644 (file)
index 0000000..313be34
--- /dev/null
@@ -0,0 +1,1371 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2004-02-26'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int dummy(){}" > $dummy.c
+       for c in cc gcc c89 ; do
+         ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1
+         if test $? = 0 ; then
+            CC_FOR_BUILD="$c"; break
+         fi
+       done
+       rm -f $dummy.c $dummy.o $dummy.rel
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # Netbsd (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       # Determine the machine/vendor (is the vendor relevant).
+       case "${UNAME_MACHINE}" in
+           amiga) machine=m68k-unknown ;;
+           arm32) machine=arm-unknown ;;
+           atari*) machine=m68k-atari ;;
+           sun3*) machine=m68k-sun ;;
+           mac68k) machine=m68k-apple ;;
+           macppc) machine=powerpc-apple ;;
+           hp3[0-9][05]) machine=m68k-hp ;;
+           ibmrt|romp-ibm) machine=romp-ibm ;;
+           *) machine=${UNAME_MACHINE}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE}" in
+           i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+              case "${HPUX_REV}" in
+                11.[0-9][0-9])
+                  if [ -x /usr/bin/getconf ]; then
+                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                        esac ;;
+                    esac
+                  fi ;;
+              esac
+              if [ "${HP_ARCH}" = "" ]; then
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+       rm -f $dummy.c $dummy
+       fi ;;
+       esac
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3D:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+int main (int argc, char *argv[]) {
+#else
+int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       ;;
+    ppc:Linux:*:*)
+       # Determine Lib Version
+       cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unknown\n");
+#endif
+  return 0;
+}
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               ./$dummy | grep 1\.99 > /dev/null
+               if test "$?" = 0 ; then LIBC="libc1" ; fi
+       fi
+       rm -f $dummy.c $dummy
+       echo powerpc-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    alpha:Linux:*:*)
+       cat <<EOF >$dummy.s
+         .data
+         \$Lformat:
+               .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+          .text
+               .globl main
+               .align 4
+               .ent main
+           main:
+               .frame \$30,16,\$26,0
+               ldgp \$29,0(\$27)
+               .prologue 1
+               .long 0x47e03d80 # implver \$0
+               lda \$2,-1
+               .long 0x47e20c21 # amask \$2,\$1
+               lda \$16,\$Lformat
+               mov \$0,\$17
+               not \$1,\$18
+               jsr \$26,printf
+               ldgp \$29,0(\$26)
+               mov 0,\$16
+               jsr \$26,exit
+               .end main
+EOF
+       LIBC=""
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+               0-0)    UNAME_MACHINE="alpha" ;;
+               1-0)    UNAME_MACHINE="alphaev5" ;;
+               1-1)    UNAME_MACHINE="alphaev56" ;;
+               1-101)  UNAME_MACHINE="alphapca56" ;;
+               2-303)  UNAME_MACHINE="alphaev6" ;;
+               2-307)  UNAME_MACHINE="alphaev67" ;;
+               esac
+               objdump --private-headers $dummy | \
+                 grep ld.so.1 > /dev/null
+               if test "$?" = 0 ; then
+                       LIBC="libc1"
+               fi
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit 0 ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_supported_emulations=`cd /; ld --help 2>&1 \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         i*86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         elf_i*86)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         i*86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+       esac
+       # Either a pre-BFD a.out linker (linux-gnuoldld)
+       # or one that does not give us useful --help.
+       # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+       # If ld does not provide *any* "supported emulations:"
+       # that means it is gnuoldld.
+       test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+       case "${UNAME_MACHINE}" in
+       i*86)
+         VENDOR=pc;
+         ;;
+       *)
+         VENDOR=unknown;
+         ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i*86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i*86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+       else
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       if test "${UNAME_MACHINE}" = "x86pc"; then
+               UNAME_MACHINE=pc
+       fi
+       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/src/deps/rtaudio-mod/config/config.sub b/src/deps/rtaudio-mod/config/config.sub
new file mode 100755 (executable)
index 0000000..9a7d59a
--- /dev/null
@@ -0,0 +1,1366 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2012-11-19'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
+               | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
+               | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 \
+               | x86 | ppcbe | mipsbe | mipsle | shbe | shle \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | hppa64 \
+               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+               | alphaev6[78] \
+               | we32k | ns16k | clipper | i370 | sh | sh[34] \
+               | powerpc | powerpc64 | powerpcle \
+               | 1750a | dsp16xx | pdp10 | pdp11 \
+               | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \
+               | v850 | c4x \
+               | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
+               | pj | pjl | h8500)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
+             | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+             | hppa2.0n-* | hppa64-* \
+             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+             | alphaev6[78]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
+             | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpc64-* | powerpcle-* \
+             | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \
+             | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
+             | [cjt]90-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
+             | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [cjt]90)
+               basic_machine=${basic_machine}-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*)        basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       pdp10-*)
+               os=-tops20
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/src/deps/rtaudio-mod/config/install.sh b/src/deps/rtaudio-mod/config/install.sh
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/src/deps/rtaudio-mod/configure b/src/deps/rtaudio-mod/configure
new file mode 100755 (executable)
index 0000000..9f3d3f8
--- /dev/null
@@ -0,0 +1,5888 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for RtAudio 4.1.
+#
+# Report bugs to <gary@music.mcgill.ca>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: gary@music.mcgill.ca about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='RtAudio'
+PACKAGE_TARNAME='rtaudio'
+PACKAGE_VERSION='4.1'
+PACKAGE_STRING='RtAudio 4.1'
+PACKAGE_BUGREPORT='gary@music.mcgill.ca'
+PACKAGE_URL=''
+
+ac_unique_file="RtAudio.cpp"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+objects
+PULSE_LIBS
+PULSE_CFLAGS
+req
+api
+libflags
+sharedname
+sharedlib
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+object_path
+cxxflag
+cppflag
+EGREP
+GREP
+CPP
+ac_ct_CC
+CFLAGS
+CC
+AR
+RANLIB
+OBJEXT
+EXEEXT
+ac_ct_CXX
+CPPFLAGS
+LDFLAGS
+CXXFLAGS
+CXX
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+GXX
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_debug
+with_jack
+with_alsa
+with_pulse
+with_oss
+with_core
+with_asio
+with_ds
+with_wasapi
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+CXX
+CXXFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CCC
+CC
+CFLAGS
+CPP
+PULSE_CFLAGS
+PULSE_LIBS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures RtAudio 4.1 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/rtaudio]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of RtAudio 4.1:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-debug = enable various debug output
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-jack = choose JACK server support (mac and linux only)
+  --with-alsa = choose native ALSA API support (linux only)
+  --with-pulse = choose PulseAudio API support (linux only)
+  --with-oss = choose OSS API support (linux only)
+  --with-jack = choose JACK server support (unix only)
+  --with-core = choose CoreAudio API support (mac only)
+  --with-asio = choose ASIO API support (windoze only)
+  --with-ds = choose DirectSound API support (windoze only)
+  --with-wasapi = choose Windows Audio Session API support (windoze only)
+
+Some influential environment variables:
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  CPP         C preprocessor
+  PULSE_CFLAGS
+              C compiler flags for PULSE, overriding pkg-config
+  PULSE_LIBS  linker flags for PULSE, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <gary@music.mcgill.ca>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+RtAudio configure 4.1
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_cxx_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------- ##
+## Report this to gary@music.mcgill.ca ##
+## ----------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by RtAudio $as_me 4.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_aux_dir=
+for ac_dir in config "$srcdir"/config; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+ac_config_files="$ac_config_files rtaudio-config librtaudio.pc Makefile tests/Makefile"
+
+
+# Fill GXX with something before test.
+GXX="no"
+
+
+
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=0.9.0
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+               PKG_CONFIG=""
+       fi
+fi
+
+
+
+# Checks for programs.
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ CC c++ cxx
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ CC c++ cxx
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5
+$as_echo_n "checking whether the C++ compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C++ compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5
+$as_echo_n "checking for C++ compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C++ compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+        CXXFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AR="$AR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_AR" && ac_cv_path_AR="no"
+  ;;
+esac
+fi
+AR=$ac_cv_path_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if [ $AR = "no" ] ; then
+    as_fn_error $? "\"Could not find ar - needed to create a library\"" "$LINENO" 5;
+fi
+
+# Checks for header files.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/ioctl.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# Check for debug
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile debug version" >&5
+$as_echo_n "checking whether to compile debug version... " >&6; }
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug; cppflag=-D__RTAUDIO_DEBUG__
+ cxxflag=-g
+ object_path=Debug
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  cppflag=
+ cxxflag=-O2
+ object_path=Release
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Checks for functions
+ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = xyes; then :
+  cppflag="$cppflag -DHAVE_GETTIMEOFDAY"
+fi
+
+
+# Set paths if prefix is defined
+if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then
+  LIBS="$LIBS -L$prefix/lib"
+  CPPFLAGS="$CPPFLAGS -I$prefix/include"
+fi
+
+# For -I and -D flags
+CPPFLAGS="$CPPFLAGS $cppflag"
+
+# For debugging and optimization ... overwrite default because it has both -g and -O2
+#CXXFLAGS="$CXXFLAGS $cxxflag"
+CXXFLAGS="$cxxflag"
+
+# Check compiler and use -Wall if gnu.
+if test $GXX = "yes" ; then
+  cxxflag="-Wall -Wextra"
+
+fi
+
+CXXFLAGS="$CXXFLAGS $cxxflag"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+sharedlib="librtaudio.so"
+
+sharedname="librtaudio.so.\$(RELEASE)"
+
+libflags="-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)"
+
+case $host in
+  *-apple*)
+  sharedlib="librtaudio.dylib"
+
+  sharedname="librtaudio.\$(RELEASE).dylib"
+
+  libflags="-dynamiclib -o librtaudio.\$(RELEASE).dylib"
+
+esac
+
+# Checks for package options and external software
+api=""
+
+req=""
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for audio API" >&5
+$as_echo_n "checking for audio API... " >&6; }
+case $host in
+  *-*-netbsd*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5
+$as_echo "using OSS" >&6; }
+    api="$api -D__LINUX_OSS__"
+    LIBS="$LIBS -lossaudio"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
+fi
+
+  ;;
+
+  *-*-linux*)
+
+# Check whether --with-jack was given.
+if test "${with_jack+set}" = set; then :
+  withval=$with_jack;
+    api="$api -D__UNIX_JACK__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5
+$as_echo "using JACK" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5
+$as_echo_n "checking for jack_client_open in -ljack... " >&6; }
+if ${ac_cv_lib_jack_jack_client_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jack_client_open ();
+int
+main ()
+{
+return jack_client_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_jack_jack_client_open=yes
+else
+  ac_cv_lib_jack_jack_client_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5
+$as_echo "$ac_cv_lib_jack_jack_client_open" >&6; }
+if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBJACK 1
+_ACEOF
+
+  LIBS="-ljack $LIBS"
+
+else
+  as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
+$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
+if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char snd_pcm_open ();
+int
+main ()
+{
+return snd_pcm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_asound_snd_pcm_open=yes
+else
+  ac_cv_lib_asound_snd_pcm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
+if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBASOUND 1
+_ACEOF
+
+  LIBS="-lasound $LIBS"
+
+else
+  as_fn_error $? "Jack support also requires the asound library!" "$LINENO" 5
+fi
+
+fi
+
+
+  # Look for ALSA flag
+
+# Check whether --with-alsa was given.
+if test "${with_alsa+set}" = set; then :
+  withval=$with_alsa;
+    api="$api -D__LINUX_ALSA__"
+    req="$req alsa"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5
+$as_echo "using ALSA" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
+$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
+if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char snd_pcm_open ();
+int
+main ()
+{
+return snd_pcm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_asound_snd_pcm_open=yes
+else
+  ac_cv_lib_asound_snd_pcm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
+if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBASOUND 1
+_ACEOF
+
+  LIBS="-lasound $LIBS"
+
+else
+  as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5
+fi
+
+fi
+
+
+  # Look for PULSE flag
+
+# Check whether --with-pulse was given.
+if test "${with_pulse+set}" = set; then :
+  withval=$with_pulse;
+    api="$api -D__LINUX_PULSE__"
+    req="$req libpulse-simple"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using PulseAudio" >&5
+$as_echo "using PulseAudio" >&6; }
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PULSE" >&5
+$as_echo_n "checking for PULSE... " >&6; }
+
+if test -n "$PULSE_CFLAGS"; then
+    pkg_cv_PULSE_CFLAGS="$PULSE_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PULSE_CFLAGS=`$PKG_CONFIG --cflags "libpulse-simple" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$PULSE_LIBS"; then
+    pkg_cv_PULSE_LIBS="$PULSE_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PULSE_LIBS=`$PKG_CONFIG --libs "libpulse-simple" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               PULSE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse-simple" 2>&1`
+        else
+               PULSE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse-simple" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$PULSE_PKG_ERRORS" >&5
+
+       as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5
+else
+       PULSE_CFLAGS=$pkg_cv_PULSE_CFLAGS
+       PULSE_LIBS=$pkg_cv_PULSE_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+        LIBS="$LIBS `pkg-config --libs libpulse-simple`"
+fi
+
+
+  # Look for OSS flag
+
+# Check whether --with-oss was given.
+if test "${with_oss+set}" = set; then :
+  withval=$with_oss;
+    api="$api -D__LINUX_OSS__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5
+$as_echo "using OSS" >&6; }
+fi
+
+
+  # If no audio api flags specified, use ALSA
+  if test "$api" == ""; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5
+$as_echo "using ALSA" >&6; }
+    api=-D__LINUX_ALSA__
+
+    req="$req alsa"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
+$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
+if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char snd_pcm_open ();
+int
+main ()
+{
+return snd_pcm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_asound_snd_pcm_open=yes
+else
+  ac_cv_lib_asound_snd_pcm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
+if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBASOUND 1
+_ACEOF
+
+  LIBS="-lasound $LIBS"
+
+else
+  as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5
+fi
+
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
+fi
+
+  ;;
+
+  *-apple*)
+
+# Check whether --with-jack was given.
+if test "${with_jack+set}" = set; then :
+  withval=$with_jack;
+    api="$api -D__UNIX_JACK__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5
+$as_echo "using JACK" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5
+$as_echo_n "checking for jack_client_open in -ljack... " >&6; }
+if ${ac_cv_lib_jack_jack_client_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jack_client_open ();
+int
+main ()
+{
+return jack_client_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_jack_jack_client_open=yes
+else
+  ac_cv_lib_jack_jack_client_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5
+$as_echo "$ac_cv_lib_jack_jack_client_open" >&6; }
+if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBJACK 1
+_ACEOF
+
+  LIBS="-ljack $LIBS"
+
+else
+  as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5
+fi
+
+fi
+
+
+#    AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] )
+#    LIBS="$LIBS -framework jackmp" ], )
+
+
+  # Look for Core flag
+
+# Check whether --with-core was given.
+if test "${with_core+set}" = set; then :
+  withval=$with_core;
+    api="$api -D__MACOSX_CORE__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5
+$as_echo "using CoreAudio" >&6; }
+    ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default"
+if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then :
+
+else
+  as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5
+fi
+
+
+    LIBS="$LIBS -framework CoreAudio -framework CoreFoundation"
+fi
+
+
+  # If no audio api flags specified, use CoreAudio
+  if test "$api" == "";  then
+    api=-D__MACOSX_CORE__
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5
+$as_echo "using CoreAudio" >&6; }
+    ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default"
+if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then :
+
+else
+  as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5
+fi
+
+
+    LIBS="-framework CoreAudio -framework CoreFoundation"
+
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
+fi
+
+  ;;
+
+  *-mingw32*)
+
+# Check whether --with-asio was given.
+if test "${with_asio+set}" = set; then :
+  withval=$with_asio;
+    api="$api -D__WINDOWS_ASIO__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ASIO" >&5
+$as_echo "using ASIO" >&6; }
+    objects="asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"
+
+fi
+
+
+  # Look for DirectSound flag
+
+# Check whether --with-ds was given.
+if test "${with_ds+set}" = set; then :
+  withval=$with_ds;
+    api="$api -D__WINDOWS_DS__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5
+$as_echo "using DirectSound" >&6; }
+    LIBS="-ldsound -lwinmm $LIBS"
+fi
+
+
+  # Look for WASAPI flag
+
+# Check whether --with-wasapi was given.
+if test "${with_wasapi+set}" = set; then :
+  withval=$with_wasapi;
+    api="$api -D__WINDOWS_WASAPI__"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using WASAPI" >&5
+$as_echo "using WASAPI" >&6; }
+    LIBS="-lwinmm -luuid -lksuser $LIBS"
+fi
+
+
+  # If no audio api flags specified, use DS
+  if test "$api" == ""; then
+    api=-D__WINDOWS_DS__
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5
+$as_echo "using DirectSound" >&6; }
+    LIBS="-ldsound -lwinmm $LIBS"
+  fi
+
+  LIBS="-lole32 $LIBS"
+  ;;
+
+  *)
+  # Default case for unknown realtime systems.
+  as_fn_error $? "Unknown system type for realtime support!" "$LINENO" 5
+  ;;
+esac
+
+CPPFLAGS="$CPPFLAGS $api"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+       cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+         mv -f confcache "$cache_file"$$ &&
+         mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+         mv -f confcache "$cache_file" ;;
+       esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[    ]*#[    ]*define[       ][      ]*\([^  (][^    (]*([^)]*)\)[   ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[    ]*#[    ]*define[       ][      ]*\([^  ][^     ]*\)[   ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[     `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+       g
+       s/^\n//
+       s/\n/ /g
+       p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by RtAudio $as_me 4.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <gary@music.mcgill.ca>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+RtAudio config.status 4.1
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "rtaudio-config") CONFIG_FILES="$CONFIG_FILES rtaudio-config" ;;
+    "librtaudio.pc") CONFIG_FILES="$CONFIG_FILES librtaudio.pc" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X "  :F $CONFIG_FILES      "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+chmod oug+x rtaudio-config
diff --git a/src/deps/rtaudio-mod/configure.ac b/src/deps/rtaudio-mod/configure.ac
new file mode 100644 (file)
index 0000000..fa45967
--- /dev/null
@@ -0,0 +1,197 @@
+# Process this file with autoconf to produce a configure script.
+AC_INIT(RtAudio, 4.1, gary@music.mcgill.ca, rtaudio)
+AC_CONFIG_AUX_DIR(config)
+AC_CONFIG_SRCDIR(RtAudio.cpp)
+AC_CONFIG_FILES([rtaudio-config librtaudio.pc Makefile tests/Makefile])
+
+# Fill GXX with something before test.
+AC_SUBST( GXX, ["no"] )
+
+dnl Check for pkg-config program, used for configuring some libraries.
+m4_define_default([PKG_PROG_PKG_CONFIG],
+[AC_MSG_CHECKING([pkg-config])
+AC_MSG_RESULT([no])])
+
+PKG_PROG_PKG_CONFIG
+
+dnl If the pkg-config autoconf support isn't installed, define its
+dnl autoconf macro to disable any packages depending on it.
+m4_define_default([PKG_CHECK_MODULES],
+[AC_MSG_CHECKING([$1])
+AC_MSG_RESULT([no])
+$4])
+
+# Checks for programs.
+AC_PROG_CXX(g++ CC c++ cxx)
+AC_PROG_RANLIB
+AC_PATH_PROG(AR, ar, no)
+if [[ $AR = "no" ]] ; then
+    AC_MSG_ERROR("Could not find ar - needed to create a library");
+fi
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sys/ioctl.h unistd.h)
+
+# Check for debug
+AC_MSG_CHECKING(whether to compile debug version)
+AC_ARG_ENABLE(debug,
+  [  --enable-debug = enable various debug output],
+  [AC_SUBST( cppflag, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cxxflag, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)],
+  [AC_SUBST( cppflag, [] ) AC_SUBST( cxxflag, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)])
+
+
+# Checks for functions
+AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], )
+
+# Set paths if prefix is defined
+if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then
+  LIBS="$LIBS -L$prefix/lib"
+  CPPFLAGS="$CPPFLAGS -I$prefix/include"
+fi
+
+# For -I and -D flags
+CPPFLAGS="$CPPFLAGS $cppflag"
+
+# For debugging and optimization ... overwrite default because it has both -g and -O2
+#CXXFLAGS="$CXXFLAGS $cxxflag"
+CXXFLAGS="$cxxflag"
+
+# Check compiler and use -Wall if gnu.
+if [test $GXX = "yes" ;] then
+  AC_SUBST( cxxflag, ["-Wall -Wextra"] )
+fi
+
+CXXFLAGS="$CXXFLAGS $cxxflag"
+
+AC_CANONICAL_HOST
+
+AC_SUBST( sharedlib, ["librtaudio.so"] )
+AC_SUBST( sharedname, ["librtaudio.so.\$(RELEASE)"] )
+AC_SUBST( libflags, ["-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)"] )
+case $host in
+  *-apple*)
+  AC_SUBST( sharedlib, ["librtaudio.dylib"] )
+  AC_SUBST( sharedname, ["librtaudio.\$(RELEASE).dylib"] )
+  AC_SUBST( libflags, ["-dynamiclib -o librtaudio.\$(RELEASE).dylib"] )
+esac
+
+# Checks for package options and external software
+AC_SUBST( api, [""] )
+AC_SUBST( req, [""] )
+AC_MSG_CHECKING(for audio API)
+case $host in
+  *-*-netbsd*)
+    AC_MSG_RESULT(using OSS)
+    api="$api -D__LINUX_OSS__"
+    LIBS="$LIBS -lossaudio"
+    AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
+  ;;
+
+  *-*-linux*)
+  AC_ARG_WITH(jack, [  --with-jack = choose JACK server support (mac and linux only)], [
+    api="$api -D__UNIX_JACK__"
+    AC_MSG_RESULT(using JACK)
+    AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))
+    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))], )
+
+  # Look for ALSA flag
+  AC_ARG_WITH(alsa, [  --with-alsa = choose native ALSA API support (linux only)], [
+    api="$api -D__LINUX_ALSA__"
+    req="$req alsa"
+    AC_MSG_RESULT(using ALSA)
+    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], )
+
+  # Look for PULSE flag
+  AC_ARG_WITH(pulse, [  --with-pulse = choose PulseAudio API support (linux only)], [
+    api="$api -D__LINUX_PULSE__"
+    req="$req libpulse-simple"
+    AC_MSG_RESULT(using PulseAudio)
+    PKG_CHECK_MODULES([PULSE], [libpulse-simple], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))
+        LIBS="$LIBS `pkg-config --libs libpulse-simple`" ], )
+
+  # Look for OSS flag
+  AC_ARG_WITH(oss, [  --with-oss = choose OSS API support (linux only)], [
+    api="$api -D__LINUX_OSS__"
+    AC_MSG_RESULT(using OSS)], )
+
+  # If no audio api flags specified, use ALSA
+  if [test "$api" == "";] then
+    AC_MSG_RESULT(using ALSA)
+    AC_SUBST( api, [-D__LINUX_ALSA__] )
+    req="$req alsa"
+    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
+  fi
+
+  AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
+  ;;
+
+  *-apple*)
+  AC_ARG_WITH(jack, [  --with-jack = choose JACK server support (unix only)], [
+    api="$api -D__UNIX_JACK__"
+    AC_MSG_RESULT(using JACK)
+    AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))], )
+
+#    AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] )
+#    LIBS="$LIBS -framework jackmp" ], )
+
+
+  # Look for Core flag
+  AC_ARG_WITH(core, [  --with-core = choose CoreAudio API support (mac only)], [
+    api="$api -D__MACOSX_CORE__"
+    AC_MSG_RESULT(using CoreAudio)
+    AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] )
+    LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ], )
+
+  # If no audio api flags specified, use CoreAudio
+  if [test "$api" == ""; ] then
+    AC_SUBST( api, [-D__MACOSX_CORE__] )
+    AC_MSG_RESULT(using CoreAudio)
+    AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
+      [],
+      [AC_MSG_ERROR(CoreAudio header files not found!)] )
+    AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] )
+  fi
+
+  AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
+  ;;
+
+  *-mingw32*)
+  AC_ARG_WITH(asio, [  --with-asio = choose ASIO API support (windoze only)], [
+    api="$api -D__WINDOWS_ASIO__"
+    AC_MSG_RESULT(using ASIO)
+    AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ], )
+
+  # Look for DirectSound flag
+  AC_ARG_WITH(ds, [  --with-ds = choose DirectSound API support (windoze only)], [
+    api="$api -D__WINDOWS_DS__"
+    AC_MSG_RESULT(using DirectSound)
+    LIBS="-ldsound -lwinmm $LIBS" ], )
+
+  # Look for WASAPI flag
+  AC_ARG_WITH(wasapi, [  --with-wasapi = choose Windows Audio Session API support (windoze only)], [
+    api="$api -D__WINDOWS_WASAPI__"
+    AC_MSG_RESULT(using WASAPI)
+    LIBS="-lwinmm -luuid -lksuser $LIBS" ], )
+
+  # If no audio api flags specified, use DS
+  if [test "$api" == "";] then
+    AC_SUBST( api, [-D__WINDOWS_DS__] )
+    AC_MSG_RESULT(using DirectSound)
+    LIBS="-ldsound -lwinmm $LIBS"
+  fi
+
+  LIBS="-lole32 $LIBS"
+  ;;
+
+  *)
+  # Default case for unknown realtime systems.
+  AC_MSG_ERROR(Unknown system type for realtime support!)
+  ;;
+esac
+
+CPPFLAGS="$CPPFLAGS $api"
+
+AC_OUTPUT
+
+chmod oug+x rtaudio-config
diff --git a/src/deps/rtaudio-mod/include/FunctionDiscoveryKeys_devpkey.h b/src/deps/rtaudio-mod/include/FunctionDiscoveryKeys_devpkey.h
new file mode 100644 (file)
index 0000000..854244d
--- /dev/null
@@ -0,0 +1,212 @@
+#pragma once
+
+/*++
+
+Copyright (c) Microsoft Corporation.  All rights reserved.
+
+Module Name:
+
+    devpkey.h
+
+Abstract:
+
+    Defines property keys for the Plug and Play Device Property API.
+
+Author:
+
+    Jim Cavalaris (jamesca) 10-14-2003
+
+Environment:
+
+    User-mode only.
+
+Revision History:
+
+    14-October-2003     jamesca
+
+        Creation and initial implementation.
+
+    20-June-2006        dougb
+
+        Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_"
+    
+--*/
+
+//#include <devpropdef.h>
+
+//
+// _NAME
+//
+
+DEFINE_PROPERTYKEY(PKEY_NAME,                          0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10);    // DEVPROP_TYPE_STRING
+
+//
+// Device properties
+// These PKEYs correspond to the old setupapi SPDRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc,             0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds,            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds,          0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Service,                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Class,                  0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid,              0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10);    // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_Driver,                 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags,            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PDOName,                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Capabilities,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17);    // DEVPROP_TYPE_UNINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumber,               0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid,            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21);    // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType,          0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusNumber,              0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName,         0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Security,               0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25);    // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS,            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26);    // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DevType,                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Exclusive,              0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Characteristics,        0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Address,                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat,     0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31);    // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PowerData,              0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32);    // DEVPROP_TYPE_BINARY
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy,          0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault,   0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride,  0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_InstallState,           0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths,          0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId,        0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38);    // DEVPROP_TYPE_GUID
+
+//
+// Device properties
+// These PKEYs correspond to a device's status and problem code
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus,          0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode,            0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3);     // DEVPROP_TYPE_UINT32
+
+//
+// Device properties
+// These PKEYs correspond to device relations
+//
+DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations,      0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations,       0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations,         0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusRelations,           0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Parent,                 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Children,               0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Siblings,               0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations,     0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11);    // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_Reported,               0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2);     // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_Legacy,                 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3);     // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_InstanceId,             0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256);   // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_ContainerId,            0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2);     // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_ModelId,                0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2);     // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4);     // DEVPROP_TYPE_UINT32
+
+DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice,   0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5);     // DEVPROP_TYPE_BOOLEAN
+
+
+DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain,         0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy,   0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node,              0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc,  0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4);     // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress,      0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9);     // DEVPROP_TYPE_BOOLEAN
+
+//
+// Device driver properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDate,             0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2);      // DEVPROP_TYPE_FILETIME
+DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion,          0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc,             0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath,          0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection,       0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt,    0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId,       0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider,         0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9);      // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers,     0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags,     0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverRank,             0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel,        0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15);     // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound,         0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17);     // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18);     // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN
+
+//
+// Device safe-removal properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired,    0xafd97640,  0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2);    // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640,  0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN
+
+
+//
+// Device properties that were set by the driver package that was installed
+// on the device.
+//
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model,                  0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite,          0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription,    0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink,      0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5);     // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon,                   0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6);     // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon,           0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7);     // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device setup class properties
+// These PKEYs correspond to the old setupapi SPCRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters,      0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters,      0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20);    // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security,          0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25);    // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS,       0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26);    // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType,           0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive,         0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28);    // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics,   0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29);    // DEVPROP_TYPE_UINT32
+
+//
+// Device setup class properties
+// These PKEYs correspond to registry values under the device class GUID key
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name,              0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2);  // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName,         0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3);  // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon,              0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4);  // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller,    0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5);  // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider,  0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6);  // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass,    0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7);  // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass,    0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8);  // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall,     0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9);  // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass,        0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService,    0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath,          0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device setup class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device interface properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName,  0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled,       0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid,     0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID
+
+//
+// Device interface class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface,  0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING
+
+
+
+
diff --git a/src/deps/rtaudio-mod/include/asio.cpp b/src/deps/rtaudio-mod/include/asio.cpp
new file mode 100644 (file)
index 0000000..b241663
--- /dev/null
@@ -0,0 +1,257 @@
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1996, Steinberg Soft- und Hardware GmbH\r
+\r
+       asio.cpp\r
+       \r
+       asio functions entries which translate the\r
+       asio interface to the asiodrvr class methods\r
+*/ \r
+       \r
+#include <string.h>\r
+#include "asiosys.h"           // platform definition\r
+#include "asio.h"\r
+\r
+#if MAC\r
+#include "asiodrvr.h"\r
+\r
+#pragma export on\r
+\r
+AsioDriver *theAsioDriver = 0;\r
+\r
+extern "C"\r
+{\r
+\r
+long main()\r
+{\r
+       return 'ASIO';\r
+}\r
+\r
+#elif WINDOWS\r
+\r
+#include "windows.h"\r
+#include "iasiodrv.h"\r
+#include "asiodrivers.h"\r
+\r
+IASIO *theAsioDriver = 0;\r
+extern AsioDrivers *asioDrivers;\r
+\r
+#elif SGI || SUN || BEOS || LINUX\r
+#include "asiodrvr.h"\r
+static AsioDriver *theAsioDriver = 0;\r
+#endif\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+ASIOError ASIOInit(ASIODriverInfo *info)\r
+{\r
+#if MAC || SGI || SUN || BEOS || LINUX\r
+       if(theAsioDriver)\r
+       {\r
+               delete theAsioDriver;\r
+               theAsioDriver = 0;\r
+       }               \r
+       info->driverVersion = 0;\r
+       strcpy(info->name, "No ASIO Driver");\r
+       theAsioDriver = getDriver();\r
+       if(!theAsioDriver)\r
+       {\r
+               strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); \r
+               return ASE_NotPresent;\r
+       }\r
+       if(!theAsioDriver->init(info->sysRef))\r
+       {\r
+               theAsioDriver->getErrorMessage(info->errorMessage);\r
+               delete theAsioDriver;\r
+               theAsioDriver = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       strcpy(info->errorMessage, "No ASIO Driver Error");\r
+       theAsioDriver->getDriverName(info->name);\r
+       info->driverVersion = theAsioDriver->getDriverVersion();\r
+       return ASE_OK;\r
+\r
+#else\r
+\r
+       info->driverVersion = 0;\r
+       strcpy(info->name, "No ASIO Driver");\r
+       if(theAsioDriver)       // must be loaded!\r
+       {\r
+               if(!theAsioDriver->init(info->sysRef))\r
+               {\r
+                       theAsioDriver->getErrorMessage(info->errorMessage);\r
+                       theAsioDriver = 0;\r
+                       return ASE_NotPresent;\r
+               }               \r
+\r
+               strcpy(info->errorMessage, "No ASIO Driver Error");\r
+               theAsioDriver->getDriverName(info->name);\r
+               info->driverVersion = theAsioDriver->getDriverVersion();\r
+               return ASE_OK;\r
+       }\r
+       return ASE_NotPresent;\r
+\r
+#endif // !MAC\r
+}\r
+\r
+ASIOError ASIOExit(void)\r
+{\r
+       if(theAsioDriver)\r
+       {\r
+#if WINDOWS\r
+               asioDrivers->removeCurrentDriver();\r
+#else\r
+               delete theAsioDriver;\r
+#endif\r
+       }               \r
+       theAsioDriver = 0;\r
+       return ASE_OK;\r
+}\r
+\r
+ASIOError ASIOStart(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->start();\r
+}\r
+\r
+ASIOError ASIOStop(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->stop();\r
+}\r
+\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *numInputChannels = *numOutputChannels = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getChannels(numInputChannels, numOutputChannels);\r
+}\r
+\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *inputLatency = *outputLatency = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getLatencies(inputLatency, outputLatency);\r
+}\r
+\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *minSize = *maxSize = *preferredSize = *granularity = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);\r
+}\r
+\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->canSampleRate(sampleRate);\r
+}\r
+\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->getSampleRate(currentRate);\r
+}\r
+\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->setSampleRate(sampleRate);\r
+}\r
+\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *numSources = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getClockSources(clocks, numSources);\r
+}\r
+\r
+ASIOError ASIOSetClockSource(long reference)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->setClockSource(reference);\r
+}\r
+\r
+ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->getSamplePosition(sPos, tStamp);\r
+}\r
+\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               info->channelGroup = -1;\r
+               info->type = ASIOSTInt16MSB;\r
+               strcpy(info->name, "None");\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getChannelInfo(info);\r
+}\r
+\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               ASIOBufferInfo *info = bufferInfos;\r
+               for(long i = 0; i < numChannels; i++, info++)\r
+                       info->buffers[0] = info->buffers[1] = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);\r
+}\r
+\r
+ASIOError ASIODisposeBuffers(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->disposeBuffers();\r
+}\r
+\r
+ASIOError ASIOControlPanel(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->controlPanel();\r
+}\r
+\r
+ASIOError ASIOFuture(long selector, void *opt)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->future(selector, opt);\r
+}\r
+\r
+ASIOError ASIOOutputReady(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->outputReady();\r
+}\r
+\r
+#if MAC\r
+}      // extern "C"\r
+#pragma export off\r
+#endif\r
+\r
+\r
diff --git a/src/deps/rtaudio-mod/include/asio.h b/src/deps/rtaudio-mod/include/asio.h
new file mode 100644 (file)
index 0000000..8ec811f
--- /dev/null
@@ -0,0 +1,1054 @@
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1997 - 2005, Steinberg Media Technologies GmbH\r
+\r
+       ASIO Interface Specification v 2.1\r
+\r
+       2005 - Added support for DSD sample data (in cooperation with Sony)\r
+\r
+\r
+       basic concept is an i/o synchronous double-buffer scheme:\r
+       \r
+       on bufferSwitch(index == 0), host will read/write:\r
+\r
+               after ASIOStart(), the\r
+  read  first input buffer A (index 0)\r
+       |   will be invalid (empty)\r
+       *   ------------------------\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Input Buffer A (0)    |   Input Buffer B (1)  |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Output Buffer A (0)   |   Output Buffer B (1) |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       *                        -------------------------\r
+       |                        before calling ASIOStart(),\r
+  write                      host will have filled output\r
+                             buffer B (index 1) already\r
+\r
+  *please* take special care of proper statement of input\r
+  and output latencies (see ASIOGetLatencies()), these\r
+  control sequencer sync accuracy\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+\r
+prototypes summary:\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+ASIOError ASIOExit(void);\r
+ASIOError ASIOStart(void);\r
+ASIOError ASIOStop(void);\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+ASIOError ASIOSetClockSource(long reference);\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+ASIOError ASIODisposeBuffers(void);\r
+ASIOError ASIOControlPanel(void);\r
+void *ASIOFuture(long selector, void *params);\r
+ASIOError ASIOOutputReady(void);\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __ASIO_H\r
+#define __ASIO_H\r
+\r
+// force 4 byte alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(push,4)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = native\r
+#endif\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Type definitions\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+// number of samples data type is 64 bit integer\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOSamples;\r
+#else\r
+       typedef struct ASIOSamples {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOSamples;\r
+#endif\r
+\r
+// Timestamp data type is 64 bit integer,\r
+// Time format is Nanoseconds.\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOTimeStamp ;\r
+#else\r
+       typedef struct ASIOTimeStamp {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOTimeStamp;\r
+#endif\r
+\r
+// Samplerates are expressed in IEEE 754 64 bit double float,\r
+// native format as host computer\r
+#if IEEE754_64FLOAT\r
+       typedef double ASIOSampleRate;\r
+#else\r
+       typedef struct ASIOSampleRate {\r
+               char ieee[8];\r
+       } ASIOSampleRate;\r
+#endif\r
+\r
+// Boolean values are expressed as long\r
+typedef long ASIOBool;\r
+enum {\r
+       ASIOFalse = 0,\r
+       ASIOTrue = 1\r
+};\r
+\r
+// Sample Types are expressed as long\r
+typedef long ASIOSampleType;\r
+enum {\r
+       ASIOSTInt16MSB   = 0,\r
+       ASIOSTInt24MSB   = 1,           // used for 20 bits as well\r
+       ASIOSTInt32MSB   = 2,\r
+       ASIOSTFloat32MSB = 3,           // IEEE 754 32 bit float\r
+       ASIOSTFloat64MSB = 4,           // IEEE 754 64 bit double float\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can be more easily used with these\r
+       ASIOSTInt32MSB16 = 8,           // 32 bit data with 16 bit alignment\r
+       ASIOSTInt32MSB18 = 9,           // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32MSB20 = 10,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32MSB24 = 11,          // 32 bit data with 24 bit alignment\r
+       \r
+       ASIOSTInt16LSB   = 16,\r
+       ASIOSTInt24LSB   = 17,          // used for 20 bits as well\r
+       ASIOSTInt32LSB   = 18,\r
+       ASIOSTFloat32LSB = 19,          // IEEE 754 32 bit float, as found on Intel x86 architecture\r
+       ASIOSTFloat64LSB = 20,          // IEEE 754 64 bit double float, as found on Intel x86 architecture\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can more easily used with these\r
+       ASIOSTInt32LSB16 = 24,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB18 = 25,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB20 = 26,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32LSB24 = 27,          // 32 bit data with 24 bit alignment\r
+\r
+       //      ASIO DSD format.\r
+       ASIOSTDSDInt8LSB1   = 32,               // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit.\r
+       ASIOSTDSDInt8MSB1   = 33,               // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit.\r
+       ASIOSTDSDInt8NER8       = 40,           // DSD 8 bit data, 1 sample per byte. No Endianness required.\r
+\r
+       ASIOSTLastEntry\r
+};\r
+\r
+/*-----------------------------------------------------------------------------\r
+// DSD operation and buffer layout\r
+// Definition by Steinberg/Sony Oxford.\r
+//\r
+// We have tried to treat DSD as PCM and so keep a consistant structure across\r
+// the ASIO interface.\r
+//\r
+// DSD's sample rate is normally referenced as a multiple of 44.1Khz, so\r
+// the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked\r
+// at making a special case for DSD and adding a field to the ASIOFuture that\r
+// would allow the user to select the Over Sampleing Rate (OSR) as a seperate\r
+// entity but decided in the end just to treat it as a simple value of\r
+// 2.8224Mhz and use the standard interface to set it.\r
+//\r
+// The second problem was the "word" size, in PCM the word size is always a\r
+// greater than or equal to 8 bits (a byte). This makes life easy as we can\r
+// then pack the samples into the "natural" size for the machine.\r
+// In DSD the "word" size is 1 bit. This is not a major problem and can easily\r
+// be dealt with if we ensure that we always deal with a multiple of 8 samples.\r
+//\r
+// DSD brings with it another twist to the Endianness religion. How are the\r
+// samples packed into the byte. It would be nice to just say the most significant\r
+// bit is always the first sample, however there would then be a performance hit\r
+// on little endian machines. Looking at how some of the processing goes...\r
+// Little endian machines like the first sample to be in the Least Significant Bit,\r
+//   this is because when you write it to memory the data is in the correct format\r
+//   to be shifted in and out of the words.\r
+// Big endian machine prefer the first sample to be in the Most Significant Bit,\r
+//   again for the same reasion.\r
+//\r
+// And just when things were looking really muddy there is a proposed extension to\r
+// DSD that uses 8 bit word sizes. It does not care what endianness you use.\r
+//\r
+// Switching the driver between DSD and PCM mode\r
+// ASIOFuture allows for extending the ASIO API quite transparently.\r
+// See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat\r
+//\r
+//-----------------------------------------------------------------------------*/\r
+\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Error codes\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef long ASIOError;\r
+enum {\r
+       ASE_OK = 0,             // This value will be returned whenever the call succeeded\r
+       ASE_SUCCESS = 0x3f4847a0,       // unique success return value for ASIOFuture calls\r
+       ASE_NotPresent = -1000, // hardware input or output is not present or available\r
+       ASE_HWMalfunction,      // hardware is malfunctioning (can be returned by any ASIO function)\r
+       ASE_InvalidParameter,   // input parameter invalid\r
+       ASE_InvalidMode,        // hardware is in a bad mode or used in a bad mode\r
+       ASE_SPNotAdvancing,     // hardware is not running when sample position is inquired\r
+       ASE_NoClock,            // sample clock or rate cannot be determined or is not present\r
+       ASE_NoMemory            // not enough memory for completing the request\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Time Info support\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOTimeCode\r
+{       \r
+       double          speed;                  // speed relation (fraction of nominal speed)\r
+                                               // optional; set to 0. or 1. if not supported\r
+       ASIOSamples     timeCodeSamples;        // time in samples\r
+       unsigned long   flags;                  // some information flags (see below)\r
+       char future[64];\r
+} ASIOTimeCode;\r
+\r
+typedef enum ASIOTimeCodeFlags\r
+{\r
+       kTcValid                = 1,\r
+       kTcRunning              = 1 << 1,\r
+       kTcReverse              = 1 << 2,\r
+       kTcOnspeed              = 1 << 3,\r
+       kTcStill                = 1 << 4,\r
+       \r
+       kTcSpeedValid           = 1 << 8\r
+}  ASIOTimeCodeFlags;\r
+\r
+typedef struct AsioTimeInfo\r
+{\r
+       double          speed;                  // absolute speed (1. = nominal)\r
+       ASIOTimeStamp   systemTime;             // system time related to samplePosition, in nanoseconds\r
+                                               // on mac, must be derived from Microseconds() (not UpTime()!)\r
+                                               // on windows, must be derived from timeGetTime()\r
+       ASIOSamples     samplePosition;\r
+       ASIOSampleRate  sampleRate;             // current rate\r
+       unsigned long flags;                    // (see below)\r
+       char reserved[12];\r
+} AsioTimeInfo;\r
+\r
+typedef enum AsioTimeInfoFlags\r
+{\r
+       kSystemTimeValid        = 1,            // must always be valid\r
+       kSamplePositionValid    = 1 << 1,       // must always be valid\r
+       kSampleRateValid        = 1 << 2,\r
+       kSpeedValid             = 1 << 3,\r
+       \r
+       kSampleRateChanged      = 1 << 4,\r
+       kClockSourceChanged     = 1 << 5\r
+} AsioTimeInfoFlags;\r
+\r
+typedef struct ASIOTime                          // both input/output\r
+{\r
+       long reserved[4];                       // must be 0\r
+       struct AsioTimeInfo     timeInfo;       // required\r
+       struct ASIOTimeCode     timeCode;       // optional, evaluated if (timeCode.flags & kTcValid)\r
+} ASIOTime;\r
+\r
+/*\r
+\r
+using time info:\r
+it is recommended to use the new method with time info even if the asio\r
+device does not support timecode; continuous calls to ASIOGetSamplePosition\r
+and ASIOGetSampleRate are avoided, and there is a more defined relationship\r
+between callback time and the time info.\r
+\r
+see the example below.\r
+to initiate time info mode, after you have received the callbacks pointer in\r
+ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo\r
+as the argument. if this returns 1, host has accepted time info mode.\r
+now host expects the new callback bufferSwitchTimeInfo to be used instead\r
+of the old bufferSwitch method. the ASIOTime structure is assumed to be valid\r
+and accessible until the callback returns.\r
+\r
+using time code:\r
+if the device supports reading time code, it will call host's asioMessage callback\r
+with kAsioSupportsTimeCode as the selector. it may then fill the according\r
+fields and set the kTcValid flag.\r
+host will call the future method with the kAsioEnableTimeCodeRead selector when\r
+it wants to enable or disable tc reading by the device. you should also support\r
+the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example).\r
+\r
+note:\r
+the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions.\r
+as a matter of convention, the relationship between the sample\r
+position counter and the time code at buffer switch time is\r
+(ignoring offset between tc and sample pos when tc is running):\r
+\r
+on input:      sample 0 -> input  buffer sample 0 -> time code 0\r
+on output:     sample 0 -> output buffer sample 0 -> time code 0\r
+\r
+this means that for 'real' calculations, one has to take into account\r
+the according latencies.\r
+\r
+example:\r
+\r
+ASIOTime asioTime;\r
+\r
+in createBuffers()\r
+{\r
+       memset(&asioTime, 0, sizeof(ASIOTime));\r
+       AsioTimeInfo* ti = &asioTime.timeInfo;\r
+       ti->sampleRate = theSampleRate;\r
+       ASIOTimeCode* tc = &asioTime.timeCode;\r
+       tc->speed = 1.;\r
+       timeInfoMode = false;\r
+       canTimeCode = false;\r
+       if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1)\r
+       {\r
+               timeInfoMode = true;\r
+#if kCanTimeCode\r
+               if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1)\r
+                       canTimeCode = true;\r
+#endif\r
+       }\r
+}\r
+\r
+void switchBuffers(long doubleBufferIndex, bool processNow)\r
+{\r
+       if(timeInfoMode)\r
+       {\r
+               AsioTimeInfo* ti = &asioTime.timeInfo;\r
+               ti->flags =     kSystemTimeValid | kSamplePositionValid | kSampleRateValid;\r
+               ti->systemTime = theNanoSeconds;\r
+               ti->samplePosition = theSamplePosition;\r
+               if(ti->sampleRate != theSampleRate)\r
+                       ti->flags |= kSampleRateChanged;\r
+               ti->sampleRate = theSampleRate;\r
+\r
+#if kCanTimeCode\r
+               if(canTimeCode && timeCodeEnabled)\r
+               {\r
+                       ASIOTimeCode* tc = &asioTime.timeCode;\r
+                       tc->timeCodeSamples = tcSamples;                                                // tc in samples\r
+                       tc->flags = kTcValid | kTcRunning | kTcOnspeed;                 // if so...\r
+               }\r
+               ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#else\r
+               callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#endif\r
+       }\r
+       else\r
+               callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse);\r
+}\r
+\r
+ASIOError ASIOFuture(long selector, void *params)\r
+{\r
+       switch(selector)\r
+       {\r
+               case kAsioEnableTimeCodeRead:\r
+                       timeCodeEnabled = true;\r
+                       return ASE_SUCCESS;\r
+               case kAsioDisableTimeCodeRead:\r
+                       timeCodeEnabled = false;\r
+                       return ASE_SUCCESS;\r
+               case kAsioCanTimeInfo:\r
+                       return ASE_SUCCESS;\r
+               #if kCanTimeCode\r
+               case kAsioCanTimeCode:\r
+                       return ASE_SUCCESS;\r
+               #endif\r
+       }\r
+       return ASE_NotPresent;\r
+};\r
+\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// application's audio stream handler callbacks\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOCallbacks\r
+{\r
+       void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess);\r
+               // bufferSwitch indicates that both input and output are to be processed.\r
+               // the current buffer half index (0 for A, 1 for B) determines\r
+               // - the output buffer that the host should start to fill. the other buffer\r
+               //   will be passed to output hardware regardless of whether it got filled\r
+               //   in time or not.\r
+               // - the input buffer that is now filled with incoming data. Note that\r
+               //   because of the synchronicity of i/o, the input always has at\r
+               //   least one buffer latency in relation to the output.\r
+               // directProcess suggests to the host whether it should immedeately\r
+               // start processing (directProcess == ASIOTrue), or whether its process\r
+               // should be deferred because the call comes from a very low level\r
+               // (for instance, a high level priority interrupt), and direct processing\r
+               // would cause timing instabilities for the rest of the system. If in doubt,\r
+               // directProcess should be set to ASIOFalse.\r
+               // Note: bufferSwitch may be called at interrupt time for highest efficiency.\r
+\r
+       void (*sampleRateDidChange) (ASIOSampleRate sRate);\r
+               // gets called when the AudioStreamIO detects a sample rate change\r
+               // If sample rate is unknown, 0 is passed (for instance, clock loss\r
+               // when externally synchronized).\r
+\r
+       long (*asioMessage) (long selector, long value, void* message, double* opt);\r
+               // generic callback for various purposes, see selectors below.\r
+               // note this is only present if the asio version is 2 or higher\r
+\r
+       ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);\r
+               // new callback with time info. makes ASIOGetSamplePosition() and various\r
+               // calls to ASIOGetSampleRate obsolete,\r
+               // and allows for timecode sync etc. to be preferred; will be used if\r
+               // the driver calls asioMessage with selector kAsioSupportsTimeInfo.\r
+} ASIOCallbacks;\r
+\r
+// asioMessage selectors\r
+enum\r
+{\r
+       kAsioSelectorSupported = 1,     // selector in <value>, returns 1L if supported,\r
+                                                               // 0 otherwise\r
+    kAsioEngineVersion,                        // returns engine (host) asio implementation version,\r
+                                                               // 2 or higher\r
+       kAsioResetRequest,                      // request driver reset. if accepted, this\r
+                                                               // will close the driver (ASIO_Exit() ) and\r
+                                                               // re-open it again (ASIO_Init() etc). some\r
+                                                               // drivers need to reconfigure for instance\r
+                                                               // when the sample rate changes, or some basic\r
+                                                               // changes have been made in ASIO_ControlPanel().\r
+                                                               // returns 1L; note the request is merely passed\r
+                                                               // to the application, there is no way to determine\r
+                                                               // if it gets accepted at this time (but it usually\r
+                                                               // will be).\r
+       kAsioBufferSizeChange,          // not yet supported, will currently always return 0L.\r
+                                                               // for now, use kAsioResetRequest instead.\r
+                                                               // once implemented, the new buffer size is expected\r
+                                                               // in <value>, and on success returns 1L\r
+       kAsioResyncRequest,                     // the driver went out of sync, such that\r
+                                                               // the timestamp is no longer valid. this\r
+                                                               // is a request to re-start the engine and\r
+                                                               // slave devices (sequencer). returns 1 for ok,\r
+                                                               // 0 if not supported.\r
+       kAsioLatenciesChanged,          // the drivers latencies have changed. The engine\r
+                                                               // will refetch the latencies.\r
+       kAsioSupportsTimeInfo,          // if host returns true here, it will expect the\r
+                                                               // callback bufferSwitchTimeInfo to be called instead\r
+                                                               // of bufferSwitch\r
+       kAsioSupportsTimeCode,          // \r
+       kAsioMMCCommand,                        // unused - value: number of commands, message points to mmc commands\r
+       kAsioSupportsInputMonitor,      // kAsioSupportsXXX return 1 if host supports this\r
+       kAsioSupportsInputGain,     // unused and undefined\r
+       kAsioSupportsInputMeter,    // unused and undefined\r
+       kAsioSupportsOutputGain,    // unused and undefined\r
+       kAsioSupportsOutputMeter,   // unused and undefined\r
+       kAsioOverload,              // driver detected an overload\r
+\r
+       kAsioNumMessageSelectors\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// (De-)Construction\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIODriverInfo\r
+{\r
+       long asioVersion;               // currently, 2\r
+       long driverVersion;             // driver specific\r
+       char name[32];\r
+       char errorMessage[124];\r
+       void *sysRef;                   // on input: system reference\r
+                                                       // (Windows: application main window handle, Mac & SGI: 0)\r
+} ASIODriverInfo;\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+/* Purpose:\r
+         Initialize the AudioStreamIO.\r
+       Parameter:\r
+         info: pointer to an ASIODriver structure:\r
+           - asioVersion:\r
+                       - on input, the host version. *** Note *** this is 0 for earlier asio\r
+                       implementations, and the asioMessage callback is implemeted\r
+                       only if asioVersion is 2 or greater. sorry but due to a design fault\r
+                       the driver doesn't have access to the host version in ASIOInit :-(\r
+                       added selector for host (engine) version in the asioMessage callback\r
+                       so we're ok from now on.\r
+                       - on return, asio implementation version.\r
+                         older versions are 1\r
+                         if you support this version (namely, ASIO_outputReady() )\r
+                         this should be 2 or higher. also see the note in\r
+                         ASIO_getTimeStamp() !\r
+           - version: on return, the driver version (format is driver specific)\r
+           - name: on return, a null-terminated string containing the driver's name\r
+               - error message: on return, should contain a user message describing\r
+                 the type of error that occured during ASIOInit(), if any.\r
+               - sysRef: platform specific\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+         ASE_NoMemory, ASE_HWMalfunction are other possible error conditions\r
+*/\r
+\r
+ASIOError ASIOExit(void);\r
+/* Purpose:\r
+         Terminates the AudioStreamIO.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes: this implies ASIOStop() and ASIODisposeBuffers(),\r
+         meaning that no host callbacks must be accessed after ASIOExit().\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Start/Stop\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOStart(void);\r
+/* Purpose:\r
+         Start input and output processing synchronously.\r
+         This will\r
+         - reset the sample counter to zero\r
+         - start the hardware (both input and output)\r
+           The first call to the hosts' bufferSwitch(index == 0) then tells\r
+           the host to read from input buffer A (index 0), and start\r
+           processing to output buffer A while output buffer B (which\r
+           has been filled by the host prior to calling ASIOStart())\r
+           is possibly sounding (see also ASIOGetLatencies()) \r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present, ASE_NotPresent\r
+         will be returned.\r
+         If the hardware fails to start, ASE_HWMalfunction will be returned.\r
+       Notes:\r
+         There is no restriction on the time that ASIOStart() takes\r
+         to perform (that is, it is not considered a realtime trigger).\r
+*/\r
+\r
+ASIOError ASIOStop(void);\r
+/* Purpose:\r
+         Stops input and output processing altogether.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes:\r
+         On return from ASIOStop(), the driver must in no\r
+         case call the hosts' bufferSwitch() routine.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Inquiry methods and sample rate\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+/* Purpose:\r
+         Returns number of individual input/output channels.\r
+       Parameter:\r
+         numInputChannels will hold the number of available input channels\r
+         numOutputChannels will hold the number of available output channels\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If only inputs, or only outputs are available, the according\r
+         other parameter will be zero, and ASE_OK is returned.\r
+*/\r
+\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+/* Purpose:\r
+         Returns the input and output latencies. This includes\r
+         device specific delays, like FIFOs etc.\r
+       Parameter:\r
+         inputLatency will hold the 'age' of the first sample frame\r
+         in the input buffer when the hosts reads it in bufferSwitch()\r
+         (this is theoretical, meaning it does not include the overhead\r
+         and delay between the actual physical switch, and the time\r
+         when bufferSitch() enters).\r
+         This will usually be the size of one block in sample frames, plus\r
+         device specific latencies.\r
+\r
+         outputLatency will specify the time between the buffer switch,\r
+         and the time when the next play buffer will start to sound.\r
+         The next play buffer is defined as the one the host starts\r
+         processing after (or at) bufferSwitch(), indicated by the\r
+         index parameter (0 for buffer A, 1 for buffer B).\r
+         It will usually be either one block, if the host writes directly\r
+         to a dma buffer, or two or more blocks if the buffer is 'latched' by\r
+         the driver. As an example, on ASIOStart(), the host will have filled\r
+         the play buffer at index 1 already; when it gets the callback (with\r
+         the parameter index == 0), this tells it to read from the input\r
+         buffer 0, and start to fill the play buffer 0 (assuming that now\r
+         play buffer 1 is already sounding). In this case, the output\r
+         latency is one block. If the driver decides to copy buffer 1\r
+         at that time, and pass it to the hardware at the next slot (which\r
+         is most commonly done, but should be avoided), the output latency\r
+         becomes two blocks instead, resulting in a total i/o latency of at least\r
+         3 blocks. As memory access is the main bottleneck in native dsp processing,\r
+         and to acheive less latency, it is highly recommended to try to avoid\r
+         copying (this is also why the driver is the owner of the buffers). To\r
+         summarize, the minimum i/o latency can be acheived if the input buffer\r
+         is processed by the host into the output buffer which will physically\r
+         start to sound on the next time slice. Also note that the host expects\r
+         the bufferSwitch() callback to be accessed for each time slice in order\r
+         to retain sync, possibly recursively; if it fails to process a block in\r
+         time, it will suspend its operation for some time in order to recover.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+/* Purpose:\r
+         Returns min, max, and preferred buffer sizes for input/output\r
+       Parameter:\r
+         minSize will hold the minimum buffer size\r
+         maxSize will hold the maxium possible buffer size\r
+         preferredSize will hold the preferred buffer size (a size which\r
+         best fits performance and hardware requirements)\r
+         granularity will hold the granularity at which buffer sizes\r
+         may differ. Usually, the buffer size will be a power of 2;\r
+         in this case, granularity will hold -1 on return, signalling\r
+         possible buffer sizes starting from minSize, increased in\r
+         powers of 2 up to maxSize.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         When minimum and maximum buffer size are equal,\r
+         the preferred buffer size has to be the same value as well; granularity\r
+         should be 0 in this case.\r
+*/\r
+\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Inquires the hardware for the available sample rates.\r
+       Parameter:\r
+         sampleRate is the rate in question.\r
+       Returns:\r
+         If the inquired sample rate is not supported, ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+/* Purpose:\r
+         Get the current sample Rate.\r
+       Parameter:\r
+         currentRate will hold the current sample rate on return.\r
+       Returns:\r
+         If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Set the hardware to the requested sample Rate. If sampleRate == 0,\r
+         enable external sync.\r
+       Parameter:\r
+         sampleRate: on input, the requested rate\r
+       Returns:\r
+         If sampleRate is unknown ASE_NoClock will be returned.\r
+         If the current clock is external, and sampleRate is != 0,\r
+         ASE_InvalidMode will be returned\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+typedef struct ASIOClockSource\r
+{\r
+       long index;                                     // as used for ASIOSetClockSource()\r
+       long associatedChannel;         // for instance, S/PDIF or AES/EBU\r
+       long associatedGroup;           // see channel groups (ASIOGetChannelInfo())\r
+       ASIOBool isCurrentSource;       // ASIOTrue if this is the current clock source\r
+       char name[32];                          // for user selection\r
+} ASIOClockSource;\r
+\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+/* Purpose:\r
+         Get the available external audio clock sources\r
+       Parameter:\r
+         clocks points to an array of ASIOClockSource structures:\r
+               - index: this is used to identify the clock source\r
+                 when ASIOSetClockSource() is accessed, should be\r
+                 an index counting from zero\r
+               - associatedInputChannel: the first channel of an associated\r
+                 input group, if any.\r
+               - associatedGroup: the group index of that channel.\r
+                 groups of channels are defined to seperate for\r
+                 instance analog, S/PDIF, AES/EBU, ADAT connectors etc,\r
+                 when present simultaniously. Note that associated channel\r
+                 is enumerated according to numInputs/numOutputs, means it\r
+                 is independant from a group (see also ASIOGetChannelInfo())\r
+                 inputs are associated to a clock if the physical connection\r
+                 transfers both data and clock (like S/PDIF, AES/EBU, or\r
+                 ADAT inputs). if there is no input channel associated with\r
+                 the clock source (like Word Clock, or internal oscillator), both\r
+                 associatedChannel and associatedGroup should be set to -1.\r
+               - isCurrentSource: on exit, ASIOTrue if this is the current clock\r
+                 source, ASIOFalse else\r
+               - name: a null-terminated string for user selection of the available sources.\r
+         numSources:\r
+             on input: the number of allocated array members\r
+             on output: the number of available clock sources, at least\r
+             1 (internal clock generator).\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetClockSource(long index);\r
+/* Purpose:\r
+         Set the audio clock source\r
+       Parameter:\r
+         index as obtained from an inquiry to ASIOGetClockSources()\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If the clock can not be selected because an input channel which\r
+         carries the current clock source is active, ASE_InvalidMode\r
+         *may* be returned (this depends on the properties of the driver\r
+         and/or hardware).\r
+       Notes:\r
+         Should *not* return ASE_NoClock if there is no clock signal present\r
+         at the selected source; this will be inquired via ASIOGetSampleRate().\r
+         It should call the host callback procedure sampleRateHasChanged(),\r
+         if the switch causes a sample rate change, or if no external clock\r
+         is present at the selected source.\r
+*/\r
+\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+/* Purpose:\r
+         Inquires the sample position/time stamp pair.\r
+       Parameter:\r
+         sPos will hold the sample position on return. The sample\r
+         position is reset to zero when ASIOStart() gets called.\r
+         tStamp will hold the system time when the sample position\r
+         was latched.\r
+       Returns:\r
+         If no input/output is present, ASE_NotPresent will be returned.\r
+         If there is no clock, ASE_SPNotAdvancing will be returned.\r
+       Notes:\r
+\r
+         in order to be able to synchronise properly,\r
+         the sample position / time stamp pair must refer to the current block,\r
+         that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch()\r
+         callback and expect the time for the current block. thus, when requested\r
+         in the very first bufferSwitch after ASIO_Start(), the sample position\r
+         should be zero, and the time stamp should refer to the very time where\r
+         the stream was started. it also means that the sample position must be\r
+         block aligned. the driver must ensure proper interpolation if the system\r
+         time can not be determined for the block position. the driver is responsible\r
+         for precise time stamps as it usually has most direct access to lower\r
+         level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies()\r
+         are essential for precise media synchronization!\r
+*/\r
+\r
+typedef struct ASIOChannelInfo\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       ASIOBool isActive;              // on exit\r
+       long channelGroup;              // dto\r
+       ASIOSampleType type;    // dto\r
+       char name[32];                  // dto\r
+} ASIOChannelInfo;\r
+\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+/* Purpose:\r
+         retreive information about the nature of a channel\r
+       Parameter:\r
+         info: pointer to a ASIOChannelInfo structure with\r
+               - channel: on input, the channel index of the channel in question.\r
+               - isInput: on input, ASIOTrue if info for an input channel is\r
+                 requested, else output\r
+               - channelGroup: on return, the channel group that the channel\r
+                 belongs to. For drivers which support different types of\r
+                 channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces,\r
+                 there should be a reasonable grouping of these types. Groups\r
+                 are always independant form a channel index, that is, a channel\r
+                 index always counts from 0 to numInputs/numOutputs regardless\r
+                 of the group it may belong to.\r
+                 There will always be at least one group (group 0). Please\r
+                 also note that by default, the host may decide to activate\r
+                 channels 0 and 1; thus, these should belong to the most\r
+                 useful type (analog i/o, if present).\r
+               - type: on return, contains the sample type of the channel\r
+               - isActive: on return, ASIOTrue if channel is active as it was\r
+                 installed by ASIOCreateBuffers(), ASIOFalse else\r
+               - name:  describing the type of channel in question. Used to allow\r
+                 for user selection, and enabling of specific channels. examples:\r
+             "Analog In", "SPDIF Out" etc\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         If possible, the string should be organised such that the first\r
+         characters are most significantly describing the nature of the\r
+         port, to allow for identification even if the view showing the\r
+         port name is too small to display more than 8 characters, for\r
+         instance.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Buffer preparation\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOBufferInfo\r
+{\r
+       ASIOBool isInput;                       // on input:  ASIOTrue: input, else output\r
+       long channelNum;                        // on input:  channel index\r
+       void *buffers[2];                       // on output: double buffer addresses\r
+} ASIOBufferInfo;\r
+\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+\r
+/* Purpose:\r
+         Allocates input/output buffers for all input and output channels to be activated.\r
+       Parameter:\r
+         bufferInfos is a pointer to an array of ASIOBufferInfo structures:\r
+           - isInput: on input, ASIOTrue if the buffer is to be allocated\r
+             for an input, output buffer else\r
+           - channelNum: on input, the index of the channel in question\r
+             (counting from 0)\r
+           - buffers: on exit, 2 pointers to the halves of the channels' double-buffer.\r
+             the size of the buffer(s) of course depend on both the ASIOSampleType\r
+             as obtained from ASIOGetChannelInfo(), and bufferSize\r
+         numChannels is the sum of all input and output channels to be created;\r
+         thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo\r
+         structures.\r
+         bufferSize selects one of the possible buffer sizes as obtained from\r
+         ASIOGetBufferSizes().\r
+         callbacks is a pointer to an ASIOCallbacks structure.\r
+       Returns:\r
+         If not enough memory is available ASE_NoMemory will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If bufferSize is not supported, or one or more of the bufferInfos elements\r
+         contain invalid settings, ASE_InvalidMode will be returned.\r
+       Notes:\r
+         If individual channel selection is not possible but requested,\r
+         the driver has to handle this. namely, bufferSwitch() will only\r
+         have filled buffers of enabled outputs. If possible, processing\r
+         and buss activities overhead should be avoided for channels which\r
+         were not enabled here.\r
+*/\r
+\r
+ASIOError ASIODisposeBuffers(void);\r
+/* Purpose:\r
+         Releases all buffers for the device.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no buffer were ever prepared, ASE_InvalidMode will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         This implies ASIOStop().\r
+*/\r
+\r
+ASIOError ASIOControlPanel(void);\r
+/* Purpose:\r
+         request the driver to start a control panel component\r
+         for device specific user settings. This will not be\r
+         accessed on some platforms (where the component is accessed\r
+         instead).\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no panel is available ASE_NotPresent will be returned.\r
+         Actually, the return code is ignored.\r
+       Notes:\r
+         if the user applied settings which require a re-configuration\r
+         of parts or all of the enigine and/or driver (such as a change of\r
+         the block size), the asioMessage callback can be used (see\r
+         ASIO_Callbacks).\r
+*/\r
+\r
+ASIOError ASIOFuture(long selector, void *params);\r
+/* Purpose:\r
+         various\r
+       Parameter:\r
+         selector: operation Code as to be defined. zero is reserved for\r
+         testing purposes.\r
+         params: depends on the selector; usually pointer to a structure\r
+         for passing and retreiving any type and amount of parameters.\r
+       Returns:\r
+         the return value is also selector dependant. if the selector\r
+         is unknown, ASE_InvalidParameter should be returned to prevent\r
+         further calls with this selector. on success, ASE_SUCCESS\r
+         must be returned (note: ASE_OK is *not* sufficient!)\r
+       Notes:\r
+         see selectors defined below.    \r
+*/\r
+\r
+enum\r
+{\r
+       kAsioEnableTimeCodeRead = 1,    // no arguments\r
+       kAsioDisableTimeCodeRead,               // no arguments\r
+       kAsioSetInputMonitor,                   // ASIOInputMonitor* in params\r
+       kAsioTransport,                                 // ASIOTransportParameters* in params\r
+       kAsioSetInputGain,                              // ASIOChannelControls* in params, apply gain\r
+       kAsioGetInputMeter,                             // ASIOChannelControls* in params, fill meter\r
+       kAsioSetOutputGain,                             // ASIOChannelControls* in params, apply gain\r
+       kAsioGetOutputMeter,                    // ASIOChannelControls* in params, fill meter\r
+       kAsioCanInputMonitor,                   // no arguments for kAsioCanXXX selectors\r
+       kAsioCanTimeInfo,\r
+       kAsioCanTimeCode,\r
+       kAsioCanTransport,\r
+       kAsioCanInputGain,\r
+       kAsioCanInputMeter,\r
+       kAsioCanOutputGain,\r
+       kAsioCanOutputMeter,\r
+\r
+       //      DSD support\r
+       //      The following extensions are required to allow switching\r
+       //      and control of the DSD subsystem.\r
+       kAsioSetIoFormat                        = 0x23111961,           /* ASIOIoFormat * in params.                    */\r
+       kAsioGetIoFormat                        = 0x23111983,           /* ASIOIoFormat * in params.                    */\r
+       kAsioCanDoIoFormat                      = 0x23112004,           /* ASIOIoFormat * in params.                    */\r
+};\r
+\r
+typedef struct ASIOInputMonitor\r
+{\r
+       long input;             // this input was set to monitor (or off), -1: all\r
+       long output;    // suggested output for monitoring the input (if so)\r
+       long gain;              // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB)\r
+       ASIOBool state; // ASIOTrue => on, ASIOFalse => off\r
+       long pan;               // suggested pan, 0 => all left, 0x7fffffff => right\r
+} ASIOInputMonitor;\r
+\r
+typedef struct ASIOChannelControls\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       long gain;                              // on input,  ranges 0 thru 0x7fffffff\r
+       long meter;                             // on return, ranges 0 thru 0x7fffffff\r
+       char future[32];\r
+} ASIOChannelControls;\r
+\r
+typedef struct ASIOTransportParameters\r
+{\r
+       long command;           // see enum below\r
+       ASIOSamples samplePosition;\r
+       long track;\r
+       long trackSwitches[16];         // 512 tracks on/off\r
+       char future[64];\r
+} ASIOTransportParameters;\r
+\r
+enum\r
+{\r
+       kTransStart = 1,\r
+       kTransStop,\r
+       kTransLocate,           // to samplePosition\r
+       kTransPunchIn,\r
+       kTransPunchOut,\r
+       kTransArmOn,            // track\r
+       kTransArmOff,           // track\r
+       kTransMonitorOn,        // track\r
+       kTransMonitorOff,       // track\r
+       kTransArm,                      // trackSwitches\r
+       kTransMonitor           // trackSwitches\r
+};\r
+\r
+/*\r
+// DSD support\r
+//     Some notes on how to use ASIOIoFormatType.\r
+//\r
+//     The caller will fill the format with the request types.\r
+//     If the board can do the request then it will leave the\r
+//     values unchanged. If the board does not support the\r
+//     request then it will change that entry to Invalid (-1)\r
+//\r
+//     So to request DSD then\r
+//\r
+//     ASIOIoFormat NeedThis={kASIODSDFormat};\r
+//\r
+//     if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){\r
+//             // If the board did not accept one of the parameters then the\r
+//             // whole call will fail and the failing parameter will\r
+//             // have had its value changes to -1.\r
+//     }\r
+//\r
+// Note: Switching between the formats need to be done before the "prepared"\r
+// state (see ASIO 2 documentation) is entered.\r
+*/\r
+typedef long int ASIOIoFormatType;\r
+enum ASIOIoFormatType_e\r
+{\r
+       kASIOFormatInvalid = -1,\r
+       kASIOPCMFormat = 0,\r
+       kASIODSDFormat = 1,\r
+};\r
+\r
+typedef struct ASIOIoFormat_s\r
+{\r
+       ASIOIoFormatType        FormatType;\r
+       char                            future[512-sizeof(ASIOIoFormatType)];\r
+} ASIOIoFormat;\r
+\r
+\r
+ASIOError ASIOOutputReady(void);\r
+/* Purpose:\r
+         this tells the driver that the host has completed processing\r
+         the output buffers. if the data format required by the hardware\r
+         differs from the supported asio formats, but the hardware\r
+         buffers are DMA buffers, the driver will have to convert\r
+         the audio stream data; as the bufferSwitch callback is\r
+         usually issued at dma block switch time, the driver will\r
+         have to convert the *previous* host buffer, which increases\r
+         the output latency by one block.\r
+         when the host finds out that ASIOOutputReady() returns\r
+         true, it will issue this call whenever it completed\r
+         output processing. then the driver can convert the\r
+         host data directly to the dma buffer to be played next,\r
+         reducing output latency by one block.\r
+         another way to look at it is, that the buffer switch is called\r
+         in order to pass the *input* stream to the host, so that it can\r
+         process the input into the output, and the output stream is passed\r
+         to the driver when the host has completed its process.\r
+       Parameter:\r
+               None\r
+       Returns:\r
+         only if the above mentioned scenario is given, and a reduction\r
+         of output latency can be acheived by this mechanism, should\r
+         ASE_OK be returned. otherwise (and usually), ASE_NotPresent\r
+         should be returned in order to prevent further calls to this\r
+         function. note that the host may want to determine if it is\r
+         to use this when the system is not yet fully initialized, so\r
+         ASE_OK should always be returned if the mechanism makes sense.          \r
+       Notes:\r
+         please remeber to adjust ASIOGetLatencies() according to\r
+         whether ASIOOutputReady() was ever called or not, if your\r
+         driver supports this scenario.\r
+         also note that the engine may fail to call ASIO_OutputReady()\r
+         in time in overload cases. as already mentioned, bufferSwitch\r
+      should be called for every block regardless of whether a block\r
+      could be processed in time.\r
+*/\r
+\r
+// restore old alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(pop)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = reset\r
+#endif\r
+\r
+#endif\r
+\r
diff --git a/src/deps/rtaudio-mod/include/asiodrivers.cpp b/src/deps/rtaudio-mod/include/asiodrivers.cpp
new file mode 100644 (file)
index 0000000..5f56454
--- /dev/null
@@ -0,0 +1,186 @@
+#include <string.h>\r
+#include "asiodrivers.h"\r
+\r
+AsioDrivers* asioDrivers = 0;\r
+\r
+bool loadAsioDriver(char *name);\r
+\r
+bool loadAsioDriver(char *name)\r
+{\r
+       if(!asioDrivers)\r
+               asioDrivers = new AsioDrivers();\r
+       if(asioDrivers)\r
+               return asioDrivers->loadDriver(name);\r
+       return false;\r
+}\r
+\r
+//------------------------------------------------------------------------------------\r
+\r
+#if MAC\r
+\r
+bool resolveASIO(unsigned long aconnID);\r
+\r
+AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')\r
+{\r
+       connID = -1;\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+       removeCurrentDriver();\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       if(curIndex >= 0)\r
+               return getName(curIndex, name);\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)\r
+               getName(i, names[i]);\r
+       return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       char dname[64];\r
+       unsigned long newID;\r
+\r
+       for(long i = 0; i < getNumFragments(); i++)\r
+       {\r
+               if(getName(i, dname) && !strcmp(name, dname))\r
+               {\r
+                       if(newInstance(i, &newID))\r
+                       {\r
+                               if(resolveASIO(newID))\r
+                               {\r
+                                       if(connID != -1)\r
+                                               removeInstance(curIndex, connID);\r
+                                       curIndex = i;\r
+                                       connID = newID;\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+       if(connID != -1)\r
+               removeInstance(curIndex, connID);\r
+       connID = -1;\r
+       curIndex = -1;\r
+}\r
+\r
+//------------------------------------------------------------------------------------\r
+\r
+#elif WINDOWS\r
+\r
+#include "iasiodrv.h"\r
+\r
+extern IASIO* theAsioDriver;\r
+\r
+AsioDrivers::AsioDrivers() : AsioDriverList()\r
+{\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       if(curIndex >= 0)\r
+               return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;\r
+       name[0] = 0;\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)\r
+               asioGetDriverName(i, names[i], 32);\r
+       return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       char dname[64];\r
+       char curName[64];\r
+\r
+       for(long i = 0; i < asioGetNumDev(); i++)\r
+       {\r
+               if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))\r
+               {\r
+                       curName[0] = 0;\r
+                       getCurrentDriverName(curName);  // in case we fail...\r
+                       removeCurrentDriver();\r
+\r
+                       if(!asioOpenDriver(i, (void **)&theAsioDriver))\r
+                       {\r
+                               curIndex = i;\r
+                               return true;\r
+                       }\r
+                       else\r
+                       {\r
+                               theAsioDriver = 0;\r
+                               if(curName[0] && strcmp(dname, curName))\r
+                                       loadDriver(curName);    // try restore\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+       if(curIndex != -1)\r
+               asioCloseDriver(curIndex);\r
+       curIndex = -1;\r
+}\r
+\r
+#elif SGI || BEOS\r
+\r
+#include "asiolist.h"\r
+\r
+AsioDrivers::AsioDrivers() \r
+       : AsioDriverList()\r
+{\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       return 0;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+}\r
+\r
+#else\r
+#error implement me\r
+#endif\r
diff --git a/src/deps/rtaudio-mod/include/asiodrivers.h b/src/deps/rtaudio-mod/include/asiodrivers.h
new file mode 100644 (file)
index 0000000..2ddf7ad
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __AsioDrivers__\r
+#define __AsioDrivers__\r
+\r
+#include "ginclude.h"\r
+\r
+#if MAC\r
+#include "CodeFragments.hpp"\r
+\r
+class AsioDrivers : public CodeFragments\r
+\r
+#elif WINDOWS\r
+#include <windows.h>\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#elif SGI || BEOS\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#else\r
+#error implement me\r
+#endif\r
+\r
+{\r
+public:\r
+       AsioDrivers();\r
+       ~AsioDrivers();\r
+       \r
+       bool getCurrentDriverName(char *name);\r
+       long getDriverNames(char **names, long maxDrivers);\r
+       bool loadDriver(char *name);\r
+       void removeCurrentDriver();\r
+       long getCurrentDriverIndex() {return curIndex;}\r
+protected:\r
+       unsigned long connID;\r
+       long curIndex;\r
+};\r
+\r
+#endif\r
diff --git a/src/deps/rtaudio-mod/include/asiodrvr.h b/src/deps/rtaudio-mod/include/asiodrvr.h
new file mode 100644 (file)
index 0000000..663f75a
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1996, Steinberg Soft- und Hardware GmbH\r
+       charlie (May 1996)\r
+\r
+       asiodrvr.h\r
+       c++ superclass to implement asio functionality. from this,\r
+       you can derive whatever required\r
+*/\r
+\r
+#ifndef _asiodrvr_\r
+#define _asiodrvr_\r
+\r
+// cpu and os system we are running on\r
+#include "asiosys.h"\r
+// basic "C" interface\r
+#include "asio.h"\r
+\r
+class AsioDriver;\r
+extern AsioDriver *getDriver();                // for generic constructor \r
+\r
+#if WINDOWS\r
+#include <windows.h>\r
+#include "combase.h"\r
+#include "iasiodrv.h"\r
+class AsioDriver : public IASIO ,public CUnknown\r
+{\r
+public:\r
+       AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);\r
+\r
+       DECLARE_IUNKNOWN\r
+       // Factory method\r
+       static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);\r
+       // IUnknown\r
+       virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);\r
+\r
+#else\r
+\r
+class AsioDriver\r
+{\r
+public:\r
+       AsioDriver();\r
+#endif\r
+       virtual ~AsioDriver();\r
+\r
+       virtual ASIOBool init(void* sysRef);\r
+       virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero\r
+       virtual long getDriverVersion();\r
+       virtual void getErrorMessage(char *string);     // max 124 bytes incl.\r
+\r
+       virtual ASIOError start();\r
+       virtual ASIOError stop();\r
+\r
+       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);\r
+       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);\r
+       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
+               long *preferredSize, long *granularity);\r
+\r
+       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);\r
+       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);\r
+       virtual ASIOError setClockSource(long reference);\r
+\r
+       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+       virtual ASIOError getChannelInfo(ASIOChannelInfo *info);\r
+\r
+       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+               long bufferSize, ASIOCallbacks *callbacks);\r
+       virtual ASIOError disposeBuffers();\r
+\r
+       virtual ASIOError controlPanel();\r
+       virtual ASIOError future(long selector, void *opt);\r
+       virtual ASIOError outputReady();\r
+};\r
+#endif\r
diff --git a/src/deps/rtaudio-mod/include/asiolist.cpp b/src/deps/rtaudio-mod/include/asiolist.cpp
new file mode 100644 (file)
index 0000000..e4c73c2
--- /dev/null
@@ -0,0 +1,308 @@
+#include <windows.h>
+#include "iasiodrv.h"
+#include "asiolist.h"
+
+#define ASIODRV_DESC           "description"
+#define INPROC_SERVER          "InprocServer32"
+#define ASIO_PATH                      "software\\asio"
+#define COM_CLSID                      "clsid"
+
+// ******************************************************************
+// Local Functions 
+// ******************************************************************
+static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
+{
+       HKEY                    hkEnum,hksub,hkpath;
+       char                    databuf[512];
+       LONG                    cr,rc = -1;
+       DWORD                   datatype,datasize;
+       DWORD                   index;
+       OFSTRUCT                ofs;
+       HFILE                   hfile;
+       BOOL                    found = FALSE;
+
+#ifdef UNICODE
+       CharLowerBuffA(clsidstr,strlen(clsidstr));
+       if ((cr = RegOpenKeyA(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
+
+               index = 0;
+               while (cr == ERROR_SUCCESS && !found) {
+                       cr = RegEnumKeyA(hkEnum,index++,databuf,512);
+                       if (cr == ERROR_SUCCESS) {
+                               CharLowerBuffA(databuf,strlen(databuf));
+                               if (!(strcmp(databuf,clsidstr))) {
+                                       if ((cr = RegOpenKeyExA(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
+                                               if ((cr = RegOpenKeyExA(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
+                                                       datatype = REG_SZ; datasize = (DWORD)dllpathsize;
+                                                       cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
+                                                       if (cr == ERROR_SUCCESS) {
+                                                               memset(&ofs,0,sizeof(OFSTRUCT));
+                                                               ofs.cBytes = sizeof(OFSTRUCT); 
+                                                               hfile = OpenFile(dllpath,&ofs,OF_EXIST);
+                                                               if (hfile) rc = 0; 
+                                                       }
+                                                       RegCloseKey(hkpath);
+                                               }
+                                               RegCloseKey(hksub);
+                                       }
+                                       found = TRUE;   // break out 
+                               }
+                       }
+               }                               
+               RegCloseKey(hkEnum);
+       }
+#else
+       CharLowerBuff(clsidstr,strlen(clsidstr));
+       if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
+
+               index = 0;
+               while (cr == ERROR_SUCCESS && !found) {
+                       cr = RegEnumKey(hkEnum,index++,databuf,512);
+                       if (cr == ERROR_SUCCESS) {
+                               CharLowerBuff(databuf,strlen(databuf));
+                               if (!(strcmp(databuf,clsidstr))) {
+                                       if ((cr = RegOpenKeyEx(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
+                                               if ((cr = RegOpenKeyEx(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
+                                                       datatype = REG_SZ; datasize = (DWORD)dllpathsize;
+                                                       cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
+                                                       if (cr == ERROR_SUCCESS) {
+                                                               memset(&ofs,0,sizeof(OFSTRUCT));
+                                                               ofs.cBytes = sizeof(OFSTRUCT); 
+                                                               hfile = OpenFile(dllpath,&ofs,OF_EXIST);
+                                                               if (hfile) rc = 0; 
+                                                       }
+                                                       RegCloseKey(hkpath);
+                                               }
+                                               RegCloseKey(hksub);
+                                       }
+                                       found = TRUE;   // break out 
+                               }
+                       }
+               }                               
+               RegCloseKey(hkEnum);
+       }
+#endif
+       return rc;
+}
+
+
+static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
+{
+       HKEY    hksub;
+       char    databuf[256];
+       char    dllpath[MAXPATHLEN];
+       WORD    wData[100];
+       CLSID   clsid;
+       DWORD   datatype,datasize;
+       LONG    cr,rc;
+
+       if (!lpdrv) {
+               if ((cr = RegOpenKeyExA(hkey,keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
+
+                       datatype = REG_SZ; datasize = 256;
+                       cr = RegQueryValueExA(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
+                       if (cr == ERROR_SUCCESS) {
+                               rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
+                               if (rc == 0) {
+                                       lpdrv = new ASIODRVSTRUCT[1];
+                                       if (lpdrv) {
+                                               memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
+                                               lpdrv->drvID = drvID;
+                                               MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
+                                               if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
+                                                       memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
+                                               }
+
+                                               datatype = REG_SZ; datasize = 256;
+                                               cr = RegQueryValueExA(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
+                                               if (cr == ERROR_SUCCESS) {
+                                                       strcpy(lpdrv->drvname,databuf);
+                                               }
+                                               else strcpy(lpdrv->drvname,keyname);
+                                       }
+                               }
+                       }
+                       RegCloseKey(hksub);
+               }
+       }       
+       else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
+
+       return lpdrv;
+}
+
+static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
+{
+       IASIO   *iasio;
+
+       if (lpdrv != 0) {
+               deleteDrvStruct(lpdrv->next);
+               if (lpdrv->asiodrv) {
+                       iasio = (IASIO *)lpdrv->asiodrv;
+                       iasio->Release();
+               }
+               delete lpdrv;
+       }
+}
+
+
+static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
+{
+       while (lpdrv) {
+               if (lpdrv->drvID == drvID) return lpdrv;
+               lpdrv = lpdrv->next;
+       }
+       return 0;
+}
+// ******************************************************************
+
+
+// ******************************************************************
+//     AsioDriverList
+// ******************************************************************
+AsioDriverList::AsioDriverList ()
+{
+       HKEY                    hkEnum = 0;
+       char                    keyname[MAXDRVNAMELEN];
+       LPASIODRVSTRUCT pdl;
+       LONG                    cr;
+       DWORD                   index = 0;
+       BOOL                    fin = FALSE;
+
+       numdrv          = 0;
+       lpdrvlist       = 0;
+
+#ifdef UNICODE
+       cr = RegOpenKeyA(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
+#else
+       cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
+#endif
+       while (cr == ERROR_SUCCESS) {
+#ifdef UNICODE
+               if ((cr = RegEnumKeyA(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
+#else
+               if ((cr = RegEnumKey(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
+#endif
+                       lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
+               }
+               else fin = TRUE;
+       }
+       if (hkEnum) RegCloseKey(hkEnum);
+
+       pdl = lpdrvlist;
+       while (pdl) {
+               numdrv++;
+               pdl = pdl->next;
+       }
+
+       if (numdrv) CoInitialize(0);    // initialize COM
+}
+
+AsioDriverList::~AsioDriverList ()
+{
+       if (numdrv) {
+               deleteDrvStruct(lpdrvlist);
+               CoUninitialize();
+       }
+}
+
+
+LONG AsioDriverList::asioGetNumDev (VOID)
+{
+       return (LONG)numdrv;
+}
+
+
+LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
+{
+       LPASIODRVSTRUCT lpdrv = 0;
+       long                    rc;
+
+       if (!asiodrv) return DRVERR_INVALID_PARAM;
+
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
+               if (!lpdrv->asiodrv) {
+                       rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
+                       if (rc == S_OK) {
+                               lpdrv->asiodrv = *asiodrv;
+                               return 0;
+                       }
+                       // else if (rc == REGDB_E_CLASSNOTREG)
+                       //      strcpy (info->messageText, "Driver not registered in the Registration Database!");
+               }
+               else rc = DRVERR_DEVICE_ALREADY_OPEN;
+       }
+       else rc = DRVERR_DEVICE_NOT_FOUND;
+       
+       return rc;
+}
+
+
+LONG AsioDriverList::asioCloseDriver (int drvID)
+{
+       LPASIODRVSTRUCT lpdrv = 0;
+       IASIO                   *iasio;
+
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
+               if (lpdrv->asiodrv) {
+                       iasio = (IASIO *)lpdrv->asiodrv;
+                       iasio->Release();
+                       lpdrv->asiodrv = 0;
+               }
+       }
+
+       return 0;
+}
+
+LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
+{      
+       LPASIODRVSTRUCT                 lpdrv = 0;
+
+       if (!drvname) return DRVERR_INVALID_PARAM;
+
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
+               if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
+                       strcpy(drvname,lpdrv->drvname);
+               }
+               else {
+                       memcpy(drvname,lpdrv->drvname,drvnamesize-4);
+                       drvname[drvnamesize-4] = '.';
+                       drvname[drvnamesize-3] = '.';
+                       drvname[drvnamesize-2] = '.';
+                       drvname[drvnamesize-1] = 0;
+               }
+               return 0;
+       }
+       return DRVERR_DEVICE_NOT_FOUND;
+}
+
+LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
+{
+       LPASIODRVSTRUCT                 lpdrv = 0;
+
+       if (!dllpath) return DRVERR_INVALID_PARAM;
+
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
+               if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
+                       strcpy(dllpath,lpdrv->dllpath);
+                       return 0;
+               }
+               dllpath[0] = 0;
+               return DRVERR_INVALID_PARAM;
+       }
+       return DRVERR_DEVICE_NOT_FOUND;
+}
+
+LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
+{
+       LPASIODRVSTRUCT                 lpdrv = 0;
+
+       if (!clsid) return DRVERR_INVALID_PARAM;
+
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
+               memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
+               return 0;
+       }
+       return DRVERR_DEVICE_NOT_FOUND;
+}
+
+
diff --git a/src/deps/rtaudio-mod/include/asiolist.h b/src/deps/rtaudio-mod/include/asiolist.h
new file mode 100644 (file)
index 0000000..01c64f0
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __asiolist__\r
+#define __asiolist__\r
+\r
+#define DRVERR                 -5000\r
+#define DRVERR_INVALID_PARAM           DRVERR-1\r
+#define DRVERR_DEVICE_ALREADY_OPEN     DRVERR-2\r
+#define DRVERR_DEVICE_NOT_FOUND                DRVERR-3\r
+\r
+#define MAXPATHLEN                     512\r
+#define MAXDRVNAMELEN          128\r
+\r
+struct asiodrvstruct\r
+{\r
+       int                                             drvID;\r
+       CLSID                                   clsid;\r
+       char                                    dllpath[MAXPATHLEN];\r
+       char                                    drvname[MAXDRVNAMELEN];\r
+       LPVOID                                  asiodrv;\r
+       struct asiodrvstruct    *next;\r
+};\r
+\r
+typedef struct asiodrvstruct ASIODRVSTRUCT;\r
+typedef ASIODRVSTRUCT  *LPASIODRVSTRUCT;\r
+\r
+class AsioDriverList {\r
+public:\r
+       AsioDriverList();\r
+       ~AsioDriverList();\r
+       \r
+       LONG asioOpenDriver (int,VOID **);\r
+       LONG asioCloseDriver (int);\r
+\r
+       // nice to have\r
+       LONG asioGetNumDev (VOID);\r
+       LONG asioGetDriverName (int,char *,int);                \r
+       LONG asioGetDriverPath (int,char *,int);\r
+       LONG asioGetDriverCLSID (int,CLSID *);\r
+\r
+       // or use directly access\r
+       LPASIODRVSTRUCT lpdrvlist;\r
+       int                             numdrv;\r
+};\r
+\r
+typedef class AsioDriverList *LPASIODRIVERLIST;\r
+\r
+#endif\r
diff --git a/src/deps/rtaudio-mod/include/asiosys.h b/src/deps/rtaudio-mod/include/asiosys.h
new file mode 100644 (file)
index 0000000..37f7a48
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __asiosys__\r
+       #define __asiosys__\r
+\r
+       #ifdef WIN32\r
+               #undef MAC \r
+               #define PPC 0\r
+               #define WINDOWS 1\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+       \r
+       #elif BEOS\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #elif SGI\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #else   // MAC\r
+\r
+               #define MAC 1\r
+               #define PPC 1\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+\r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+       #endif\r
+\r
+#endif\r
diff --git a/src/deps/rtaudio-mod/include/dsound.h b/src/deps/rtaudio-mod/include/dsound.h
new file mode 100644 (file)
index 0000000..cb19cca
--- /dev/null
@@ -0,0 +1,2369 @@
+/*==========================================================================;
+ *
+ *  Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ *  File:       dsound.h
+ *  Content:    DirectSound include file
+ *
+ **************************************************************************/
+
+#define COM_NO_WINDOWS_H
+#include <objbase.h>
+#include <float.h>
+
+#ifndef DIRECTSOUND_VERSION
+#define DIRECTSOUND_VERSION 0x0900  /* Version 9.0 */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#ifndef __DSOUND_INCLUDED__
+#define __DSOUND_INCLUDED__
+
+/* Type definitions shared with Direct3D */
+
+#ifndef DX_SHARED_DEFINES
+
+typedef float D3DVALUE, *LPD3DVALUE;
+
+#ifndef D3DCOLOR_DEFINED
+typedef DWORD D3DCOLOR;
+#define D3DCOLOR_DEFINED
+#endif
+
+#ifndef LPD3DCOLOR_DEFINED
+typedef DWORD *LPD3DCOLOR;
+#define LPD3DCOLOR_DEFINED
+#endif
+
+#ifndef D3DVECTOR_DEFINED
+typedef struct _D3DVECTOR {
+    float x;
+    float y;
+    float z;
+} D3DVECTOR;
+#define D3DVECTOR_DEFINED
+#endif
+
+#ifndef LPD3DVECTOR_DEFINED
+typedef D3DVECTOR *LPD3DVECTOR;
+#define LPD3DVECTOR_DEFINED
+#endif
+
+#define DX_SHARED_DEFINES
+#endif // DX_SHARED_DEFINES
+
+#define _FACDS  0x878   /* DirectSound's facility code */
+#define MAKE_DSHRESULT(code)  MAKE_HRESULT(1, _FACDS, code)
+
+// DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000}
+DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
+
+// DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B}
+DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b);
+
+// DirectSound Capture Component GUID {B0210780-89CD-11D0-AF08-00A0C925CD16}
+DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
+
+// DirectSound 8.0 Capture Component GUID {E4BCAC13-7F99-4908-9A8E-74E3BF24B6E1}
+DEFINE_GUID(CLSID_DirectSoundCapture8, 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1);
+
+// DirectSound Full Duplex Component GUID {FEA4300C-7959-4147-B26A-2377B9E7A91D}
+DEFINE_GUID(CLSID_DirectSoundFullDuplex, 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d);
+
+
+// DirectSound default playback device GUID {DEF00000-9C6D-47ED-AAF1-4DDA8F2B5C03}
+DEFINE_GUID(DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
+
+// DirectSound default capture device GUID {DEF00001-9C6D-47ED-AAF1-4DDA8F2B5C03}
+DEFINE_GUID(DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
+
+// DirectSound default device for voice playback {DEF00002-9C6D-47ED-AAF1-4DDA8F2B5C03}
+DEFINE_GUID(DSDEVID_DefaultVoicePlayback, 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
+
+// DirectSound default device for voice capture {DEF00003-9C6D-47ED-AAF1-4DDA8F2B5C03}
+DEFINE_GUID(DSDEVID_DefaultVoiceCapture, 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
+
+
+//
+// Forward declarations for interfaces.
+// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined
+//
+
+#ifdef __cplusplus
+struct IDirectSound;
+struct IDirectSoundBuffer;
+struct IDirectSound3DListener;
+struct IDirectSound3DBuffer;
+struct IDirectSoundCapture;
+struct IDirectSoundCaptureBuffer;
+struct IDirectSoundNotify;
+#endif // __cplusplus
+
+
+//
+// DirectSound 8.0 interfaces.
+//
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+#ifdef __cplusplus
+struct IDirectSound8;
+struct IDirectSoundBuffer8;
+struct IDirectSoundCaptureBuffer8;
+struct IDirectSoundFXGargle;
+struct IDirectSoundFXChorus;
+struct IDirectSoundFXFlanger;
+struct IDirectSoundFXEcho;
+struct IDirectSoundFXDistortion;
+struct IDirectSoundFXCompressor;
+struct IDirectSoundFXParamEq;
+struct IDirectSoundFXWavesReverb;
+struct IDirectSoundFXI3DL2Reverb;
+struct IDirectSoundCaptureFXAec;
+struct IDirectSoundCaptureFXNoiseSuppress;
+struct IDirectSoundFullDuplex;
+#endif // __cplusplus
+
+// IDirectSound8, IDirectSoundBuffer8 and IDirectSoundCaptureBuffer8 are the
+// only DirectSound 7.0 interfaces with changed functionality in version 8.0.
+// The other level 8 interfaces as equivalent to their level 7 counterparts:
+
+#define IDirectSoundCapture8            IDirectSoundCapture
+#define IDirectSound3DListener8         IDirectSound3DListener
+#define IDirectSound3DBuffer8           IDirectSound3DBuffer
+#define IDirectSoundNotify8             IDirectSoundNotify
+#define IDirectSoundFXGargle8           IDirectSoundFXGargle
+#define IDirectSoundFXChorus8           IDirectSoundFXChorus
+#define IDirectSoundFXFlanger8          IDirectSoundFXFlanger
+#define IDirectSoundFXEcho8             IDirectSoundFXEcho
+#define IDirectSoundFXDistortion8       IDirectSoundFXDistortion
+#define IDirectSoundFXCompressor8       IDirectSoundFXCompressor
+#define IDirectSoundFXParamEq8          IDirectSoundFXParamEq
+#define IDirectSoundFXWavesReverb8      IDirectSoundFXWavesReverb
+#define IDirectSoundFXI3DL2Reverb8      IDirectSoundFXI3DL2Reverb
+#define IDirectSoundCaptureFXAec8       IDirectSoundCaptureFXAec
+#define IDirectSoundCaptureFXNoiseSuppress8 IDirectSoundCaptureFXNoiseSuppress
+#define IDirectSoundFullDuplex8         IDirectSoundFullDuplex
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+typedef struct IDirectSound                 *LPDIRECTSOUND;
+typedef struct IDirectSoundBuffer           *LPDIRECTSOUNDBUFFER;
+typedef struct IDirectSound3DListener       *LPDIRECTSOUND3DLISTENER;
+typedef struct IDirectSound3DBuffer         *LPDIRECTSOUND3DBUFFER;
+typedef struct IDirectSoundCapture          *LPDIRECTSOUNDCAPTURE;
+typedef struct IDirectSoundCaptureBuffer    *LPDIRECTSOUNDCAPTUREBUFFER;
+typedef struct IDirectSoundNotify           *LPDIRECTSOUNDNOTIFY;
+
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+typedef struct IDirectSoundFXGargle         *LPDIRECTSOUNDFXGARGLE;
+typedef struct IDirectSoundFXChorus         *LPDIRECTSOUNDFXCHORUS;
+typedef struct IDirectSoundFXFlanger        *LPDIRECTSOUNDFXFLANGER;
+typedef struct IDirectSoundFXEcho           *LPDIRECTSOUNDFXECHO;
+typedef struct IDirectSoundFXDistortion     *LPDIRECTSOUNDFXDISTORTION;
+typedef struct IDirectSoundFXCompressor     *LPDIRECTSOUNDFXCOMPRESSOR;
+typedef struct IDirectSoundFXParamEq        *LPDIRECTSOUNDFXPARAMEQ;
+typedef struct IDirectSoundFXWavesReverb    *LPDIRECTSOUNDFXWAVESREVERB;
+typedef struct IDirectSoundFXI3DL2Reverb    *LPDIRECTSOUNDFXI3DL2REVERB;
+typedef struct IDirectSoundCaptureFXAec     *LPDIRECTSOUNDCAPTUREFXAEC;
+typedef struct IDirectSoundCaptureFXNoiseSuppress *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS;
+typedef struct IDirectSoundFullDuplex       *LPDIRECTSOUNDFULLDUPLEX;
+
+typedef struct IDirectSound8                *LPDIRECTSOUND8;
+typedef struct IDirectSoundBuffer8          *LPDIRECTSOUNDBUFFER8;
+typedef struct IDirectSound3DListener8      *LPDIRECTSOUND3DLISTENER8;
+typedef struct IDirectSound3DBuffer8        *LPDIRECTSOUND3DBUFFER8;
+typedef struct IDirectSoundCapture8         *LPDIRECTSOUNDCAPTURE8;
+typedef struct IDirectSoundCaptureBuffer8   *LPDIRECTSOUNDCAPTUREBUFFER8;
+typedef struct IDirectSoundNotify8          *LPDIRECTSOUNDNOTIFY8;
+typedef struct IDirectSoundFXGargle8        *LPDIRECTSOUNDFXGARGLE8;
+typedef struct IDirectSoundFXChorus8        *LPDIRECTSOUNDFXCHORUS8;
+typedef struct IDirectSoundFXFlanger8       *LPDIRECTSOUNDFXFLANGER8;
+typedef struct IDirectSoundFXEcho8          *LPDIRECTSOUNDFXECHO8;
+typedef struct IDirectSoundFXDistortion8    *LPDIRECTSOUNDFXDISTORTION8;
+typedef struct IDirectSoundFXCompressor8    *LPDIRECTSOUNDFXCOMPRESSOR8;
+typedef struct IDirectSoundFXParamEq8       *LPDIRECTSOUNDFXPARAMEQ8;
+typedef struct IDirectSoundFXWavesReverb8   *LPDIRECTSOUNDFXWAVESREVERB8;
+typedef struct IDirectSoundFXI3DL2Reverb8   *LPDIRECTSOUNDFXI3DL2REVERB8;
+typedef struct IDirectSoundCaptureFXAec8    *LPDIRECTSOUNDCAPTUREFXAEC8;
+typedef struct IDirectSoundCaptureFXNoiseSuppress8 *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS8;
+typedef struct IDirectSoundFullDuplex8      *LPDIRECTSOUNDFULLDUPLEX8;
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IID definitions for the unchanged DirectSound 8.0 interfaces
+//
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+#define IID_IDirectSoundCapture8            IID_IDirectSoundCapture
+#define IID_IDirectSound3DListener8         IID_IDirectSound3DListener
+#define IID_IDirectSound3DBuffer8           IID_IDirectSound3DBuffer
+#define IID_IDirectSoundNotify8             IID_IDirectSoundNotify
+#define IID_IDirectSoundFXGargle8           IID_IDirectSoundFXGargle
+#define IID_IDirectSoundFXChorus8           IID_IDirectSoundFXChorus
+#define IID_IDirectSoundFXFlanger8          IID_IDirectSoundFXFlanger
+#define IID_IDirectSoundFXEcho8             IID_IDirectSoundFXEcho
+#define IID_IDirectSoundFXDistortion8       IID_IDirectSoundFXDistortion
+#define IID_IDirectSoundFXCompressor8       IID_IDirectSoundFXCompressor
+#define IID_IDirectSoundFXParamEq8          IID_IDirectSoundFXParamEq
+#define IID_IDirectSoundFXWavesReverb8      IID_IDirectSoundFXWavesReverb
+#define IID_IDirectSoundFXI3DL2Reverb8      IID_IDirectSoundFXI3DL2Reverb
+#define IID_IDirectSoundCaptureFXAec8       IID_IDirectSoundCaptureFXAec
+#define IID_IDirectSoundCaptureFXNoiseSuppress8 IID_IDirectSoundCaptureFXNoiseSuppress
+#define IID_IDirectSoundFullDuplex8         IID_IDirectSoundFullDuplex
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// Compatibility typedefs
+//
+
+#ifndef _LPCWAVEFORMATEX_DEFINED
+#define _LPCWAVEFORMATEX_DEFINED
+typedef const WAVEFORMATEX *LPCWAVEFORMATEX;
+#endif // _LPCWAVEFORMATEX_DEFINED
+
+#ifndef __LPCGUID_DEFINED__
+#define __LPCGUID_DEFINED__
+typedef const GUID *LPCGUID;
+#endif // __LPCGUID_DEFINED__
+
+typedef LPDIRECTSOUND *LPLPDIRECTSOUND;
+typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER;
+typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER;
+typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER;
+typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE;
+typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER;
+typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY;
+
+#if DIRECTSOUND_VERSION >= 0x0800
+typedef LPDIRECTSOUND8 *LPLPDIRECTSOUND8;
+typedef LPDIRECTSOUNDBUFFER8 *LPLPDIRECTSOUNDBUFFER8;
+typedef LPDIRECTSOUNDCAPTURE8 *LPLPDIRECTSOUNDCAPTURE8;
+typedef LPDIRECTSOUNDCAPTUREBUFFER8 *LPLPDIRECTSOUNDCAPTUREBUFFER8;
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// Structures
+//
+
+typedef struct _DSCAPS
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwMinSecondarySampleRate;
+    DWORD           dwMaxSecondarySampleRate;
+    DWORD           dwPrimaryBuffers;
+    DWORD           dwMaxHwMixingAllBuffers;
+    DWORD           dwMaxHwMixingStaticBuffers;
+    DWORD           dwMaxHwMixingStreamingBuffers;
+    DWORD           dwFreeHwMixingAllBuffers;
+    DWORD           dwFreeHwMixingStaticBuffers;
+    DWORD           dwFreeHwMixingStreamingBuffers;
+    DWORD           dwMaxHw3DAllBuffers;
+    DWORD           dwMaxHw3DStaticBuffers;
+    DWORD           dwMaxHw3DStreamingBuffers;
+    DWORD           dwFreeHw3DAllBuffers;
+    DWORD           dwFreeHw3DStaticBuffers;
+    DWORD           dwFreeHw3DStreamingBuffers;
+    DWORD           dwTotalHwMemBytes;
+    DWORD           dwFreeHwMemBytes;
+    DWORD           dwMaxContigFreeHwMemBytes;
+    DWORD           dwUnlockTransferRateHwBuffers;
+    DWORD           dwPlayCpuOverheadSwBuffers;
+    DWORD           dwReserved1;
+    DWORD           dwReserved2;
+} DSCAPS, *LPDSCAPS;
+
+typedef const DSCAPS *LPCDSCAPS;
+
+typedef struct _DSBCAPS
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwUnlockTransferRate;
+    DWORD           dwPlayCpuOverhead;
+} DSBCAPS, *LPDSBCAPS;
+
+typedef const DSBCAPS *LPCDSBCAPS;
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+    typedef struct _DSEFFECTDESC
+    {
+        DWORD       dwSize;
+        DWORD       dwFlags;
+        GUID        guidDSFXClass;
+        DWORD_PTR   dwReserved1;
+        DWORD_PTR   dwReserved2;
+    } DSEFFECTDESC, *LPDSEFFECTDESC;
+    typedef const DSEFFECTDESC *LPCDSEFFECTDESC;
+
+    #define DSFX_LOCHARDWARE    0x00000001
+    #define DSFX_LOCSOFTWARE    0x00000002
+
+    enum
+    {
+        DSFXR_PRESENT,          // 0
+        DSFXR_LOCHARDWARE,      // 1
+        DSFXR_LOCSOFTWARE,      // 2
+        DSFXR_UNALLOCATED,      // 3
+        DSFXR_FAILED,           // 4
+        DSFXR_UNKNOWN,          // 5
+        DSFXR_SENDLOOP          // 6
+    };
+
+    typedef struct _DSCEFFECTDESC
+    {
+        DWORD       dwSize;
+        DWORD       dwFlags;
+        GUID        guidDSCFXClass;
+        GUID        guidDSCFXInstance;
+        DWORD       dwReserved1;
+        DWORD       dwReserved2;
+    } DSCEFFECTDESC, *LPDSCEFFECTDESC;
+    typedef const DSCEFFECTDESC *LPCDSCEFFECTDESC;
+
+    #define DSCFX_LOCHARDWARE   0x00000001
+    #define DSCFX_LOCSOFTWARE   0x00000002
+
+    #define DSCFXR_LOCHARDWARE  0x00000010
+    #define DSCFXR_LOCSOFTWARE  0x00000020
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+typedef struct _DSBUFFERDESC
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwReserved;
+    LPWAVEFORMATEX  lpwfxFormat;
+#if DIRECTSOUND_VERSION >= 0x0700
+    GUID            guid3DAlgorithm;
+#endif
+} DSBUFFERDESC, *LPDSBUFFERDESC;
+
+typedef const DSBUFFERDESC *LPCDSBUFFERDESC;
+
+// Older version of this structure:
+
+typedef struct _DSBUFFERDESC1
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwReserved;
+    LPWAVEFORMATEX  lpwfxFormat;
+} DSBUFFERDESC1, *LPDSBUFFERDESC1;
+
+typedef const DSBUFFERDESC1 *LPCDSBUFFERDESC1;
+
+typedef struct _DS3DBUFFER
+{
+    DWORD           dwSize;
+    D3DVECTOR       vPosition;
+    D3DVECTOR       vVelocity;
+    DWORD           dwInsideConeAngle;
+    DWORD           dwOutsideConeAngle;
+    D3DVECTOR       vConeOrientation;
+    LONG            lConeOutsideVolume;
+    D3DVALUE        flMinDistance;
+    D3DVALUE        flMaxDistance;
+    DWORD           dwMode;
+} DS3DBUFFER, *LPDS3DBUFFER;
+
+typedef const DS3DBUFFER *LPCDS3DBUFFER;
+
+typedef struct _DS3DLISTENER
+{
+    DWORD           dwSize;
+    D3DVECTOR       vPosition;
+    D3DVECTOR       vVelocity;
+    D3DVECTOR       vOrientFront;
+    D3DVECTOR       vOrientTop;
+    D3DVALUE        flDistanceFactor;
+    D3DVALUE        flRolloffFactor;
+    D3DVALUE        flDopplerFactor;
+} DS3DLISTENER, *LPDS3DLISTENER;
+
+typedef const DS3DLISTENER *LPCDS3DLISTENER;
+
+typedef struct _DSCCAPS
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwFormats;
+    DWORD           dwChannels;
+} DSCCAPS, *LPDSCCAPS;
+
+typedef const DSCCAPS *LPCDSCCAPS;
+
+typedef struct _DSCBUFFERDESC1
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwReserved;
+    LPWAVEFORMATEX  lpwfxFormat;
+} DSCBUFFERDESC1, *LPDSCBUFFERDESC1;
+
+typedef struct _DSCBUFFERDESC
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwReserved;
+    LPWAVEFORMATEX  lpwfxFormat;
+#if DIRECTSOUND_VERSION >= 0x0800
+    DWORD           dwFXCount;
+    LPDSCEFFECTDESC lpDSCFXDesc;
+#endif
+} DSCBUFFERDESC, *LPDSCBUFFERDESC;
+
+typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC;
+
+typedef struct _DSCBCAPS
+{
+    DWORD           dwSize;
+    DWORD           dwFlags;
+    DWORD           dwBufferBytes;
+    DWORD           dwReserved;
+} DSCBCAPS, *LPDSCBCAPS;
+
+typedef const DSCBCAPS *LPCDSCBCAPS;
+
+typedef struct _DSBPOSITIONNOTIFY
+{
+    DWORD           dwOffset;
+    HANDLE          hEventNotify;
+} DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY;
+
+typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY;
+
+//
+// DirectSound API
+//
+
+typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID);
+typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID);
+
+extern HRESULT WINAPI DirectSoundCreate(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
+extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
+extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
+
+extern HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC, LPUNKNOWN pUnkOuter);
+extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
+extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
+
+#if DIRECTSOUND_VERSION >= 0x0800
+extern HRESULT WINAPI DirectSoundCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter);
+extern HRESULT WINAPI DirectSoundCaptureCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter);
+extern HRESULT WINAPI DirectSoundFullDuplexCreate(LPCGUID pcGuidCaptureDevice, LPCGUID pcGuidRenderDevice,
+        LPCDSCBUFFERDESC pcDSCBufferDesc, LPCDSBUFFERDESC pcDSBufferDesc, HWND hWnd,
+        DWORD dwLevel, LPDIRECTSOUNDFULLDUPLEX* ppDSFD, LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
+        LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, LPUNKNOWN pUnkOuter);
+#define DirectSoundFullDuplexCreate8 DirectSoundFullDuplexCreate
+
+extern HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest);
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+#ifdef UNICODE
+#define LPDSENUMCALLBACK            LPDSENUMCALLBACKW
+#define DirectSoundEnumerate        DirectSoundEnumerateW
+#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW
+#else // UNICODE
+#define LPDSENUMCALLBACK            LPDSENUMCALLBACKA
+#define DirectSoundEnumerate        DirectSoundEnumerateA
+#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA
+#endif // UNICODE
+
+//
+// IUnknown
+//
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#ifndef IUnknown_QueryInterface
+#define IUnknown_QueryInterface(p,a,b)  (p)->lpVtbl->QueryInterface(p,a,b)
+#endif // IUnknown_QueryInterface
+#ifndef IUnknown_AddRef
+#define IUnknown_AddRef(p)              (p)->lpVtbl->AddRef(p)
+#endif // IUnknown_AddRef
+#ifndef IUnknown_Release
+#define IUnknown_Release(p)             (p)->lpVtbl->Release(p)
+#endif // IUnknown_Release
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#ifndef IUnknown_QueryInterface
+#define IUnknown_QueryInterface(p,a,b)  (p)->QueryInterface(a,b)
+#endif // IUnknown_QueryInterface
+#ifndef IUnknown_AddRef
+#define IUnknown_AddRef(p)              (p)->AddRef()
+#endif // IUnknown_AddRef
+#ifndef IUnknown_Release
+#define IUnknown_Release(p)             (p)->Release()
+#endif // IUnknown_Release
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#ifndef __IReferenceClock_INTERFACE_DEFINED__
+#define __IReferenceClock_INTERFACE_DEFINED__
+
+typedef LONGLONG REFERENCE_TIME;
+typedef REFERENCE_TIME *LPREFERENCE_TIME;
+
+DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+
+#undef INTERFACE
+#define INTERFACE IReferenceClock
+
+DECLARE_INTERFACE_(IReferenceClock, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IReferenceClock methods
+    STDMETHOD(GetTime)              (THIS_ REFERENCE_TIME *pTime) PURE;
+    STDMETHOD(AdviseTime)           (THIS_ REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime,
+                                           HANDLE hEvent, LPDWORD pdwAdviseCookie) PURE;
+    STDMETHOD(AdvisePeriodic)       (THIS_ REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime,
+                                           HANDLE hSemaphore, LPDWORD pdwAdviseCookie) PURE;
+    STDMETHOD(Unadvise)             (THIS_ DWORD dwAdviseCookie) PURE;
+};
+
+#endif // __IReferenceClock_INTERFACE_DEFINED__
+
+#ifndef IReferenceClock_QueryInterface
+
+#define IReferenceClock_QueryInterface(p,a,b)      IUnknown_QueryInterface(p,a,b)
+#define IReferenceClock_AddRef(p)                  IUnknown_AddRef(p)
+#define IReferenceClock_Release(p)                 IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IReferenceClock_GetTime(p,a)               (p)->lpVtbl->GetTime(p,a)
+#define IReferenceClock_AdviseTime(p,a,b,c,d)      (p)->lpVtbl->AdviseTime(p,a,b,c,d)
+#define IReferenceClock_AdvisePeriodic(p,a,b,c,d)  (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d)
+#define IReferenceClock_Unadvise(p,a)              (p)->lpVtbl->Unadvise(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IReferenceClock_GetTime(p,a)               (p)->GetTime(a)
+#define IReferenceClock_AdviseTime(p,a,b,c,d)      (p)->AdviseTime(a,b,c,d)
+#define IReferenceClock_AdvisePeriodic(p,a,b,c,d)  (p)->AdvisePeriodic(a,b,c,d)
+#define IReferenceClock_Unadvise(p,a)              (p)->Unadvise(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // IReferenceClock_QueryInterface
+
+//
+// IDirectSound
+//
+
+DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
+
+#undef INTERFACE
+#define INTERFACE IDirectSound
+
+DECLARE_INTERFACE_(IDirectSound, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSound methods
+    STDMETHOD(CreateSoundBuffer)    (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE;
+    STDMETHOD(GetCaps)              (THIS_ LPDSCAPS pDSCaps) PURE;
+    STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE;
+    STDMETHOD(SetCooperativeLevel)  (THIS_ HWND hwnd, DWORD dwLevel) PURE;
+    STDMETHOD(Compact)              (THIS) PURE;
+    STDMETHOD(GetSpeakerConfig)     (THIS_ LPDWORD pdwSpeakerConfig) PURE;
+    STDMETHOD(SetSpeakerConfig)     (THIS_ DWORD dwSpeakerConfig) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPCGUID pcGuidDevice) PURE;
+};
+
+#define IDirectSound_QueryInterface(p,a,b)       IUnknown_QueryInterface(p,a,b)
+#define IDirectSound_AddRef(p)                   IUnknown_AddRef(p)
+#define IDirectSound_Release(p)                  IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound_CreateSoundBuffer(p,a,b,c)  (p)->lpVtbl->CreateSoundBuffer(p,a,b,c)
+#define IDirectSound_GetCaps(p,a)                (p)->lpVtbl->GetCaps(p,a)
+#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b)
+#define IDirectSound_SetCooperativeLevel(p,a,b)  (p)->lpVtbl->SetCooperativeLevel(p,a,b)
+#define IDirectSound_Compact(p)                  (p)->lpVtbl->Compact(p)
+#define IDirectSound_GetSpeakerConfig(p,a)       (p)->lpVtbl->GetSpeakerConfig(p,a)
+#define IDirectSound_SetSpeakerConfig(p,b)       (p)->lpVtbl->SetSpeakerConfig(p,b)
+#define IDirectSound_Initialize(p,a)             (p)->lpVtbl->Initialize(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound_CreateSoundBuffer(p,a,b,c)  (p)->CreateSoundBuffer(a,b,c)
+#define IDirectSound_GetCaps(p,a)                (p)->GetCaps(a)
+#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b)
+#define IDirectSound_SetCooperativeLevel(p,a,b)  (p)->SetCooperativeLevel(a,b)
+#define IDirectSound_Compact(p)                  (p)->Compact()
+#define IDirectSound_GetSpeakerConfig(p,a)       (p)->GetSpeakerConfig(a)
+#define IDirectSound_SetSpeakerConfig(p,b)       (p)->SetSpeakerConfig(b)
+#define IDirectSound_Initialize(p,a)             (p)->Initialize(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSound8
+//
+
+DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66);
+
+#undef INTERFACE
+#define INTERFACE IDirectSound8
+
+DECLARE_INTERFACE_(IDirectSound8, IDirectSound)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSound methods
+    STDMETHOD(CreateSoundBuffer)    (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE;
+    STDMETHOD(GetCaps)              (THIS_ LPDSCAPS pDSCaps) PURE;
+    STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE;
+    STDMETHOD(SetCooperativeLevel)  (THIS_ HWND hwnd, DWORD dwLevel) PURE;
+    STDMETHOD(Compact)              (THIS) PURE;
+    STDMETHOD(GetSpeakerConfig)     (THIS_ LPDWORD pdwSpeakerConfig) PURE;
+    STDMETHOD(SetSpeakerConfig)     (THIS_ DWORD dwSpeakerConfig) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPCGUID pcGuidDevice) PURE;
+
+    // IDirectSound8 methods
+    STDMETHOD(VerifyCertification)  (THIS_ LPDWORD pdwCertified) PURE;
+};
+
+#define IDirectSound8_QueryInterface(p,a,b)       IDirectSound_QueryInterface(p,a,b)
+#define IDirectSound8_AddRef(p)                   IDirectSound_AddRef(p)
+#define IDirectSound8_Release(p)                  IDirectSound_Release(p)
+#define IDirectSound8_CreateSoundBuffer(p,a,b,c)  IDirectSound_CreateSoundBuffer(p,a,b,c)
+#define IDirectSound8_GetCaps(p,a)                IDirectSound_GetCaps(p,a)
+#define IDirectSound8_DuplicateSoundBuffer(p,a,b) IDirectSound_DuplicateSoundBuffer(p,a,b)
+#define IDirectSound8_SetCooperativeLevel(p,a,b)  IDirectSound_SetCooperativeLevel(p,a,b)
+#define IDirectSound8_Compact(p)                  IDirectSound_Compact(p)
+#define IDirectSound8_GetSpeakerConfig(p,a)       IDirectSound_GetSpeakerConfig(p,a)
+#define IDirectSound8_SetSpeakerConfig(p,a)       IDirectSound_SetSpeakerConfig(p,a)
+#define IDirectSound8_Initialize(p,a)             IDirectSound_Initialize(p,a)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound8_VerifyCertification(p,a)           (p)->lpVtbl->VerifyCertification(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound8_VerifyCertification(p,a)           (p)->VerifyCertification(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSoundBuffer
+//
+
+DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundBuffer
+
+DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundBuffer methods
+    STDMETHOD(GetCaps)              (THIS_ LPDSBCAPS pDSBufferCaps) PURE;
+    STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE;
+    STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE;
+    STDMETHOD(GetVolume)            (THIS_ LPLONG plVolume) PURE;
+    STDMETHOD(GetPan)               (THIS_ LPLONG plPan) PURE;
+    STDMETHOD(GetFrequency)         (THIS_ LPDWORD pdwFrequency) PURE;
+    STDMETHOD(GetStatus)            (THIS_ LPDWORD pdwStatus) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE;
+    STDMETHOD(Lock)                 (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1,
+                                           LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE;
+    STDMETHOD(Play)                 (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE;
+    STDMETHOD(SetCurrentPosition)   (THIS_ DWORD dwNewPosition) PURE;
+    STDMETHOD(SetFormat)            (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE;
+    STDMETHOD(SetVolume)            (THIS_ LONG lVolume) PURE;
+    STDMETHOD(SetPan)               (THIS_ LONG lPan) PURE;
+    STDMETHOD(SetFrequency)         (THIS_ DWORD dwFrequency) PURE;
+    STDMETHOD(Stop)                 (THIS) PURE;
+    STDMETHOD(Unlock)               (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE;
+    STDMETHOD(Restore)              (THIS) PURE;
+};
+
+#define IDirectSoundBuffer_QueryInterface(p,a,b)        IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundBuffer_AddRef(p)                    IUnknown_AddRef(p)
+#define IDirectSoundBuffer_Release(p)                   IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundBuffer_GetCaps(p,a)                 (p)->lpVtbl->GetCaps(p,a)
+#define IDirectSoundBuffer_GetCurrentPosition(p,a,b)    (p)->lpVtbl->GetCurrentPosition(p,a,b)
+#define IDirectSoundBuffer_GetFormat(p,a,b,c)           (p)->lpVtbl->GetFormat(p,a,b,c)
+#define IDirectSoundBuffer_GetVolume(p,a)               (p)->lpVtbl->GetVolume(p,a)
+#define IDirectSoundBuffer_GetPan(p,a)                  (p)->lpVtbl->GetPan(p,a)
+#define IDirectSoundBuffer_GetFrequency(p,a)            (p)->lpVtbl->GetFrequency(p,a)
+#define IDirectSoundBuffer_GetStatus(p,a)               (p)->lpVtbl->GetStatus(p,a)
+#define IDirectSoundBuffer_Initialize(p,a,b)            (p)->lpVtbl->Initialize(p,a,b)
+#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g)        (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g)
+#define IDirectSoundBuffer_Play(p,a,b,c)                (p)->lpVtbl->Play(p,a,b,c)
+#define IDirectSoundBuffer_SetCurrentPosition(p,a)      (p)->lpVtbl->SetCurrentPosition(p,a)
+#define IDirectSoundBuffer_SetFormat(p,a)               (p)->lpVtbl->SetFormat(p,a)
+#define IDirectSoundBuffer_SetVolume(p,a)               (p)->lpVtbl->SetVolume(p,a)
+#define IDirectSoundBuffer_SetPan(p,a)                  (p)->lpVtbl->SetPan(p,a)
+#define IDirectSoundBuffer_SetFrequency(p,a)            (p)->lpVtbl->SetFrequency(p,a)
+#define IDirectSoundBuffer_Stop(p)                      (p)->lpVtbl->Stop(p)
+#define IDirectSoundBuffer_Unlock(p,a,b,c,d)            (p)->lpVtbl->Unlock(p,a,b,c,d)
+#define IDirectSoundBuffer_Restore(p)                   (p)->lpVtbl->Restore(p)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundBuffer_GetCaps(p,a)                 (p)->GetCaps(a)
+#define IDirectSoundBuffer_GetCurrentPosition(p,a,b)    (p)->GetCurrentPosition(a,b)
+#define IDirectSoundBuffer_GetFormat(p,a,b,c)           (p)->GetFormat(a,b,c)
+#define IDirectSoundBuffer_GetVolume(p,a)               (p)->GetVolume(a)
+#define IDirectSoundBuffer_GetPan(p,a)                  (p)->GetPan(a)
+#define IDirectSoundBuffer_GetFrequency(p,a)            (p)->GetFrequency(a)
+#define IDirectSoundBuffer_GetStatus(p,a)               (p)->GetStatus(a)
+#define IDirectSoundBuffer_Initialize(p,a,b)            (p)->Initialize(a,b)
+#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g)        (p)->Lock(a,b,c,d,e,f,g)
+#define IDirectSoundBuffer_Play(p,a,b,c)                (p)->Play(a,b,c)
+#define IDirectSoundBuffer_SetCurrentPosition(p,a)      (p)->SetCurrentPosition(a)
+#define IDirectSoundBuffer_SetFormat(p,a)               (p)->SetFormat(a)
+#define IDirectSoundBuffer_SetVolume(p,a)               (p)->SetVolume(a)
+#define IDirectSoundBuffer_SetPan(p,a)                  (p)->SetPan(a)
+#define IDirectSoundBuffer_SetFrequency(p,a)            (p)->SetFrequency(a)
+#define IDirectSoundBuffer_Stop(p)                      (p)->Stop()
+#define IDirectSoundBuffer_Unlock(p,a,b,c,d)            (p)->Unlock(a,b,c,d)
+#define IDirectSoundBuffer_Restore(p)                   (p)->Restore()
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSoundBuffer8
+//
+
+DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundBuffer8
+
+DECLARE_INTERFACE_(IDirectSoundBuffer8, IDirectSoundBuffer)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundBuffer methods
+    STDMETHOD(GetCaps)              (THIS_ LPDSBCAPS pDSBufferCaps) PURE;
+    STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE;
+    STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE;
+    STDMETHOD(GetVolume)            (THIS_ LPLONG plVolume) PURE;
+    STDMETHOD(GetPan)               (THIS_ LPLONG plPan) PURE;
+    STDMETHOD(GetFrequency)         (THIS_ LPDWORD pdwFrequency) PURE;
+    STDMETHOD(GetStatus)            (THIS_ LPDWORD pdwStatus) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE;
+    STDMETHOD(Lock)                 (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1,
+                                           LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE;
+    STDMETHOD(Play)                 (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE;
+    STDMETHOD(SetCurrentPosition)   (THIS_ DWORD dwNewPosition) PURE;
+    STDMETHOD(SetFormat)            (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE;
+    STDMETHOD(SetVolume)            (THIS_ LONG lVolume) PURE;
+    STDMETHOD(SetPan)               (THIS_ LONG lPan) PURE;
+    STDMETHOD(SetFrequency)         (THIS_ DWORD dwFrequency) PURE;
+    STDMETHOD(Stop)                 (THIS) PURE;
+    STDMETHOD(Unlock)               (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE;
+    STDMETHOD(Restore)              (THIS) PURE;
+
+    // IDirectSoundBuffer8 methods
+    STDMETHOD(SetFX)                (THIS_ DWORD dwEffectsCount, LPDSEFFECTDESC pDSFXDesc, LPDWORD pdwResultCodes) PURE;
+    STDMETHOD(AcquireResources)     (THIS_ DWORD dwFlags, DWORD dwEffectsCount, LPDWORD pdwResultCodes) PURE;
+    STDMETHOD(GetObjectInPath)      (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE;
+};
+
+// Special GUID meaning "select all objects" for use in GetObjectInPath()
+DEFINE_GUID(GUID_All_Objects, 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5);
+
+#define IDirectSoundBuffer8_QueryInterface(p,a,b)           IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundBuffer8_AddRef(p)                       IUnknown_AddRef(p)
+#define IDirectSoundBuffer8_Release(p)                      IUnknown_Release(p)
+
+#define IDirectSoundBuffer8_GetCaps(p,a)                    IDirectSoundBuffer_GetCaps(p,a)
+#define IDirectSoundBuffer8_GetCurrentPosition(p,a,b)       IDirectSoundBuffer_GetCurrentPosition(p,a,b)
+#define IDirectSoundBuffer8_GetFormat(p,a,b,c)              IDirectSoundBuffer_GetFormat(p,a,b,c)
+#define IDirectSoundBuffer8_GetVolume(p,a)                  IDirectSoundBuffer_GetVolume(p,a)
+#define IDirectSoundBuffer8_GetPan(p,a)                     IDirectSoundBuffer_GetPan(p,a)
+#define IDirectSoundBuffer8_GetFrequency(p,a)               IDirectSoundBuffer_GetFrequency(p,a)
+#define IDirectSoundBuffer8_GetStatus(p,a)                  IDirectSoundBuffer_GetStatus(p,a)
+#define IDirectSoundBuffer8_Initialize(p,a,b)               IDirectSoundBuffer_Initialize(p,a,b)
+#define IDirectSoundBuffer8_Lock(p,a,b,c,d,e,f,g)           IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g)
+#define IDirectSoundBuffer8_Play(p,a,b,c)                   IDirectSoundBuffer_Play(p,a,b,c)
+#define IDirectSoundBuffer8_SetCurrentPosition(p,a)         IDirectSoundBuffer_SetCurrentPosition(p,a)
+#define IDirectSoundBuffer8_SetFormat(p,a)                  IDirectSoundBuffer_SetFormat(p,a)
+#define IDirectSoundBuffer8_SetVolume(p,a)                  IDirectSoundBuffer_SetVolume(p,a)
+#define IDirectSoundBuffer8_SetPan(p,a)                     IDirectSoundBuffer_SetPan(p,a)
+#define IDirectSoundBuffer8_SetFrequency(p,a)               IDirectSoundBuffer_SetFrequency(p,a)
+#define IDirectSoundBuffer8_Stop(p)                         IDirectSoundBuffer_Stop(p)
+#define IDirectSoundBuffer8_Unlock(p,a,b,c,d)               IDirectSoundBuffer_Unlock(p,a,b,c,d)
+#define IDirectSoundBuffer8_Restore(p)                      IDirectSoundBuffer_Restore(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundBuffer8_SetFX(p,a,b,c)                  (p)->lpVtbl->SetFX(p,a,b,c)
+#define IDirectSoundBuffer8_AcquireResources(p,a,b,c)       (p)->lpVtbl->AcquireResources(p,a,b,c)
+#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d)      (p)->lpVtbl->GetObjectInPath(p,a,b,c,d)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundBuffer8_SetFX(p,a,b,c)                  (p)->SetFX(a,b,c)
+#define IDirectSoundBuffer8_AcquireResources(p,a,b,c)       (p)->AcquireResources(a,b,c)
+#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d)      (p)->GetObjectInPath(a,b,c,d)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSound3DListener
+//
+
+DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
+
+#undef INTERFACE
+#define INTERFACE IDirectSound3DListener
+
+DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)           (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)            (THIS) PURE;
+    STDMETHOD_(ULONG,Release)           (THIS) PURE;
+
+    // IDirectSound3DListener methods
+    STDMETHOD(GetAllParameters)         (THIS_ LPDS3DLISTENER pListener) PURE;
+    STDMETHOD(GetDistanceFactor)        (THIS_ D3DVALUE* pflDistanceFactor) PURE;
+    STDMETHOD(GetDopplerFactor)         (THIS_ D3DVALUE* pflDopplerFactor) PURE;
+    STDMETHOD(GetOrientation)           (THIS_ D3DVECTOR* pvOrientFront, D3DVECTOR* pvOrientTop) PURE;
+    STDMETHOD(GetPosition)              (THIS_ D3DVECTOR* pvPosition) PURE;
+    STDMETHOD(GetRolloffFactor)         (THIS_ D3DVALUE* pflRolloffFactor) PURE;
+    STDMETHOD(GetVelocity)              (THIS_ D3DVECTOR* pvVelocity) PURE;
+    STDMETHOD(SetAllParameters)         (THIS_ LPCDS3DLISTENER pcListener, DWORD dwApply) PURE;
+    STDMETHOD(SetDistanceFactor)        (THIS_ D3DVALUE flDistanceFactor, DWORD dwApply) PURE;
+    STDMETHOD(SetDopplerFactor)         (THIS_ D3DVALUE flDopplerFactor, DWORD dwApply) PURE;
+    STDMETHOD(SetOrientation)           (THIS_ D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
+                                               D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD dwApply) PURE;
+    STDMETHOD(SetPosition)              (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE;
+    STDMETHOD(SetRolloffFactor)         (THIS_ D3DVALUE flRolloffFactor, DWORD dwApply) PURE;
+    STDMETHOD(SetVelocity)              (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE;
+    STDMETHOD(CommitDeferredSettings)   (THIS) PURE;
+};
+
+#define IDirectSound3DListener_QueryInterface(p,a,b)            IUnknown_QueryInterface(p,a,b)
+#define IDirectSound3DListener_AddRef(p)                        IUnknown_AddRef(p)
+#define IDirectSound3DListener_Release(p)                       IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound3DListener_GetAllParameters(p,a)            (p)->lpVtbl->GetAllParameters(p,a)
+#define IDirectSound3DListener_GetDistanceFactor(p,a)           (p)->lpVtbl->GetDistanceFactor(p,a)
+#define IDirectSound3DListener_GetDopplerFactor(p,a)            (p)->lpVtbl->GetDopplerFactor(p,a)
+#define IDirectSound3DListener_GetOrientation(p,a,b)            (p)->lpVtbl->GetOrientation(p,a,b)
+#define IDirectSound3DListener_GetPosition(p,a)                 (p)->lpVtbl->GetPosition(p,a)
+#define IDirectSound3DListener_GetRolloffFactor(p,a)            (p)->lpVtbl->GetRolloffFactor(p,a)
+#define IDirectSound3DListener_GetVelocity(p,a)                 (p)->lpVtbl->GetVelocity(p,a)
+#define IDirectSound3DListener_SetAllParameters(p,a,b)          (p)->lpVtbl->SetAllParameters(p,a,b)
+#define IDirectSound3DListener_SetDistanceFactor(p,a,b)         (p)->lpVtbl->SetDistanceFactor(p,a,b)
+#define IDirectSound3DListener_SetDopplerFactor(p,a,b)          (p)->lpVtbl->SetDopplerFactor(p,a,b)
+#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g)  (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g)
+#define IDirectSound3DListener_SetPosition(p,a,b,c,d)           (p)->lpVtbl->SetPosition(p,a,b,c,d)
+#define IDirectSound3DListener_SetRolloffFactor(p,a,b)          (p)->lpVtbl->SetRolloffFactor(p,a,b)
+#define IDirectSound3DListener_SetVelocity(p,a,b,c,d)           (p)->lpVtbl->SetVelocity(p,a,b,c,d)
+#define IDirectSound3DListener_CommitDeferredSettings(p)        (p)->lpVtbl->CommitDeferredSettings(p)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound3DListener_GetAllParameters(p,a)            (p)->GetAllParameters(a)
+#define IDirectSound3DListener_GetDistanceFactor(p,a)           (p)->GetDistanceFactor(a)
+#define IDirectSound3DListener_GetDopplerFactor(p,a)            (p)->GetDopplerFactor(a)
+#define IDirectSound3DListener_GetOrientation(p,a,b)            (p)->GetOrientation(a,b)
+#define IDirectSound3DListener_GetPosition(p,a)                 (p)->GetPosition(a)
+#define IDirectSound3DListener_GetRolloffFactor(p,a)            (p)->GetRolloffFactor(a)
+#define IDirectSound3DListener_GetVelocity(p,a)                 (p)->GetVelocity(a)
+#define IDirectSound3DListener_SetAllParameters(p,a,b)          (p)->SetAllParameters(a,b)
+#define IDirectSound3DListener_SetDistanceFactor(p,a,b)         (p)->SetDistanceFactor(a,b)
+#define IDirectSound3DListener_SetDopplerFactor(p,a,b)          (p)->SetDopplerFactor(a,b)
+#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g)  (p)->SetOrientation(a,b,c,d,e,f,g)
+#define IDirectSound3DListener_SetPosition(p,a,b,c,d)           (p)->SetPosition(a,b,c,d)
+#define IDirectSound3DListener_SetRolloffFactor(p,a,b)          (p)->SetRolloffFactor(a,b)
+#define IDirectSound3DListener_SetVelocity(p,a,b,c,d)           (p)->SetVelocity(a,b,c,d)
+#define IDirectSound3DListener_CommitDeferredSettings(p)        (p)->CommitDeferredSettings()
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSound3DBuffer
+//
+
+DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
+
+#undef INTERFACE
+#define INTERFACE IDirectSound3DBuffer
+
+DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSound3DBuffer methods
+    STDMETHOD(GetAllParameters)     (THIS_ LPDS3DBUFFER pDs3dBuffer) PURE;
+    STDMETHOD(GetConeAngles)        (THIS_ LPDWORD pdwInsideConeAngle, LPDWORD pdwOutsideConeAngle) PURE;
+    STDMETHOD(GetConeOrientation)   (THIS_ D3DVECTOR* pvOrientation) PURE;
+    STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG plConeOutsideVolume) PURE;
+    STDMETHOD(GetMaxDistance)       (THIS_ D3DVALUE* pflMaxDistance) PURE;
+    STDMETHOD(GetMinDistance)       (THIS_ D3DVALUE* pflMinDistance) PURE;
+    STDMETHOD(GetMode)              (THIS_ LPDWORD pdwMode) PURE;
+    STDMETHOD(GetPosition)          (THIS_ D3DVECTOR* pvPosition) PURE;
+    STDMETHOD(GetVelocity)          (THIS_ D3DVECTOR* pvVelocity) PURE;
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDS3DBUFFER pcDs3dBuffer, DWORD dwApply) PURE;
+    STDMETHOD(SetConeAngles)        (THIS_ DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD dwApply) PURE;
+    STDMETHOD(SetConeOrientation)   (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE;
+    STDMETHOD(SetConeOutsideVolume) (THIS_ LONG lConeOutsideVolume, DWORD dwApply) PURE;
+    STDMETHOD(SetMaxDistance)       (THIS_ D3DVALUE flMaxDistance, DWORD dwApply) PURE;
+    STDMETHOD(SetMinDistance)       (THIS_ D3DVALUE flMinDistance, DWORD dwApply) PURE;
+    STDMETHOD(SetMode)              (THIS_ DWORD dwMode, DWORD dwApply) PURE;
+    STDMETHOD(SetPosition)          (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE;
+    STDMETHOD(SetVelocity)          (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE;
+};
+
+#define IDirectSound3DBuffer_QueryInterface(p,a,b)          IUnknown_QueryInterface(p,a,b)
+#define IDirectSound3DBuffer_AddRef(p)                      IUnknown_AddRef(p)
+#define IDirectSound3DBuffer_Release(p)                     IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound3DBuffer_GetAllParameters(p,a)          (p)->lpVtbl->GetAllParameters(p,a)
+#define IDirectSound3DBuffer_GetConeAngles(p,a,b)           (p)->lpVtbl->GetConeAngles(p,a,b)
+#define IDirectSound3DBuffer_GetConeOrientation(p,a)        (p)->lpVtbl->GetConeOrientation(p,a)
+#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a)      (p)->lpVtbl->GetConeOutsideVolume(p,a)
+#define IDirectSound3DBuffer_GetPosition(p,a)               (p)->lpVtbl->GetPosition(p,a)
+#define IDirectSound3DBuffer_GetMinDistance(p,a)            (p)->lpVtbl->GetMinDistance(p,a)
+#define IDirectSound3DBuffer_GetMaxDistance(p,a)            (p)->lpVtbl->GetMaxDistance(p,a)
+#define IDirectSound3DBuffer_GetMode(p,a)                   (p)->lpVtbl->GetMode(p,a)
+#define IDirectSound3DBuffer_GetVelocity(p,a)               (p)->lpVtbl->GetVelocity(p,a)
+#define IDirectSound3DBuffer_SetAllParameters(p,a,b)        (p)->lpVtbl->SetAllParameters(p,a,b)
+#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c)         (p)->lpVtbl->SetConeAngles(p,a,b,c)
+#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d)  (p)->lpVtbl->SetConeOrientation(p,a,b,c,d)
+#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b)    (p)->lpVtbl->SetConeOutsideVolume(p,a,b)
+#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d)         (p)->lpVtbl->SetPosition(p,a,b,c,d)
+#define IDirectSound3DBuffer_SetMinDistance(p,a,b)          (p)->lpVtbl->SetMinDistance(p,a,b)
+#define IDirectSound3DBuffer_SetMaxDistance(p,a,b)          (p)->lpVtbl->SetMaxDistance(p,a,b)
+#define IDirectSound3DBuffer_SetMode(p,a,b)                 (p)->lpVtbl->SetMode(p,a,b)
+#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d)         (p)->lpVtbl->SetVelocity(p,a,b,c,d)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSound3DBuffer_GetAllParameters(p,a)          (p)->GetAllParameters(a)
+#define IDirectSound3DBuffer_GetConeAngles(p,a,b)           (p)->GetConeAngles(a,b)
+#define IDirectSound3DBuffer_GetConeOrientation(p,a)        (p)->GetConeOrientation(a)
+#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a)      (p)->GetConeOutsideVolume(a)
+#define IDirectSound3DBuffer_GetPosition(p,a)               (p)->GetPosition(a)
+#define IDirectSound3DBuffer_GetMinDistance(p,a)            (p)->GetMinDistance(a)
+#define IDirectSound3DBuffer_GetMaxDistance(p,a)            (p)->GetMaxDistance(a)
+#define IDirectSound3DBuffer_GetMode(p,a)                   (p)->GetMode(a)
+#define IDirectSound3DBuffer_GetVelocity(p,a)               (p)->GetVelocity(a)
+#define IDirectSound3DBuffer_SetAllParameters(p,a,b)        (p)->SetAllParameters(a,b)
+#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c)         (p)->SetConeAngles(a,b,c)
+#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d)  (p)->SetConeOrientation(a,b,c,d)
+#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b)    (p)->SetConeOutsideVolume(a,b)
+#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d)         (p)->SetPosition(a,b,c,d)
+#define IDirectSound3DBuffer_SetMinDistance(p,a,b)          (p)->SetMinDistance(a,b)
+#define IDirectSound3DBuffer_SetMaxDistance(p,a,b)          (p)->SetMaxDistance(a,b)
+#define IDirectSound3DBuffer_SetMode(p,a,b)                 (p)->SetMode(a,b)
+#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d)         (p)->SetVelocity(a,b,c,d)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundCapture
+//
+
+DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundCapture
+
+DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundCapture methods
+    STDMETHOD(CreateCaptureBuffer)  (THIS_ LPCDSCBUFFERDESC pcDSCBufferDesc, LPDIRECTSOUNDCAPTUREBUFFER *ppDSCBuffer, LPUNKNOWN pUnkOuter) PURE;
+    STDMETHOD(GetCaps)              (THIS_ LPDSCCAPS pDSCCaps) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPCGUID pcGuidDevice) PURE;
+};
+
+#define IDirectSoundCapture_QueryInterface(p,a,b)           IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundCapture_AddRef(p)                       IUnknown_AddRef(p)
+#define IDirectSoundCapture_Release(p)                      IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c)    (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c)
+#define IDirectSoundCapture_GetCaps(p,a)                    (p)->lpVtbl->GetCaps(p,a)
+#define IDirectSoundCapture_Initialize(p,a)                 (p)->lpVtbl->Initialize(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c)    (p)->CreateCaptureBuffer(a,b,c)
+#define IDirectSoundCapture_GetCaps(p,a)                    (p)->GetCaps(a)
+#define IDirectSoundCapture_Initialize(p,a)                 (p)->Initialize(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundCaptureBuffer
+//
+
+DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundCaptureBuffer
+
+DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundCaptureBuffer methods
+    STDMETHOD(GetCaps)              (THIS_ LPDSCBCAPS pDSCBCaps) PURE;
+    STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE;
+    STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE;
+    STDMETHOD(GetStatus)            (THIS_ LPDWORD pdwStatus) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE;
+    STDMETHOD(Lock)                 (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1,
+                                           LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE;
+    STDMETHOD(Start)                (THIS_ DWORD dwFlags) PURE;
+    STDMETHOD(Stop)                 (THIS) PURE;
+    STDMETHOD(Unlock)               (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE;
+};
+
+#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b)         IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundCaptureBuffer_AddRef(p)                     IUnknown_AddRef(p)
+#define IDirectSoundCaptureBuffer_Release(p)                    IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureBuffer_GetCaps(p,a)                  (p)->lpVtbl->GetCaps(p,a)
+#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b)     (p)->lpVtbl->GetCurrentPosition(p,a,b)
+#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c)            (p)->lpVtbl->GetFormat(p,a,b,c)
+#define IDirectSoundCaptureBuffer_GetStatus(p,a)                (p)->lpVtbl->GetStatus(p,a)
+#define IDirectSoundCaptureBuffer_Initialize(p,a,b)             (p)->lpVtbl->Initialize(p,a,b)
+#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g)         (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g)
+#define IDirectSoundCaptureBuffer_Start(p,a)                    (p)->lpVtbl->Start(p,a)
+#define IDirectSoundCaptureBuffer_Stop(p)                       (p)->lpVtbl->Stop(p)
+#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d)             (p)->lpVtbl->Unlock(p,a,b,c,d)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureBuffer_GetCaps(p,a)                  (p)->GetCaps(a)
+#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b)     (p)->GetCurrentPosition(a,b)
+#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c)            (p)->GetFormat(a,b,c)
+#define IDirectSoundCaptureBuffer_GetStatus(p,a)                (p)->GetStatus(a)
+#define IDirectSoundCaptureBuffer_Initialize(p,a,b)             (p)->Initialize(a,b)
+#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g)         (p)->Lock(a,b,c,d,e,f,g)
+#define IDirectSoundCaptureBuffer_Start(p,a)                    (p)->Start(a)
+#define IDirectSoundCaptureBuffer_Stop(p)                       (p)->Stop()
+#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d)             (p)->Unlock(a,b,c,d)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSoundCaptureBuffer8
+//
+
+DEFINE_GUID(IID_IDirectSoundCaptureBuffer8, 0x990df4, 0xdbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundCaptureBuffer8
+
+DECLARE_INTERFACE_(IDirectSoundCaptureBuffer8, IDirectSoundCaptureBuffer)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundCaptureBuffer methods
+    STDMETHOD(GetCaps)              (THIS_ LPDSCBCAPS pDSCBCaps) PURE;
+    STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE;
+    STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE;
+    STDMETHOD(GetStatus)            (THIS_ LPDWORD pdwStatus) PURE;
+    STDMETHOD(Initialize)           (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE;
+    STDMETHOD(Lock)                 (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1,
+                                           LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE;
+    STDMETHOD(Start)                (THIS_ DWORD dwFlags) PURE;
+    STDMETHOD(Stop)                 (THIS) PURE;
+    STDMETHOD(Unlock)               (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE;
+
+    // IDirectSoundCaptureBuffer8 methods
+    STDMETHOD(GetObjectInPath)      (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE;
+    STDMETHOD(GetFXStatus)          (DWORD dwFXCount, LPDWORD pdwFXStatus) PURE;
+};
+
+#define IDirectSoundCaptureBuffer8_QueryInterface(p,a,b)            IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundCaptureBuffer8_AddRef(p)                        IUnknown_AddRef(p)
+#define IDirectSoundCaptureBuffer8_Release(p)                       IUnknown_Release(p)
+
+#define IDirectSoundCaptureBuffer8_GetCaps(p,a)                     IDirectSoundCaptureBuffer_GetCaps(p,a)
+#define IDirectSoundCaptureBuffer8_GetCurrentPosition(p,a,b)        IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b)
+#define IDirectSoundCaptureBuffer8_GetFormat(p,a,b,c)               IDirectSoundCaptureBuffer_GetFormat(p,a,b,c)
+#define IDirectSoundCaptureBuffer8_GetStatus(p,a)                   IDirectSoundCaptureBuffer_GetStatus(p,a)
+#define IDirectSoundCaptureBuffer8_Initialize(p,a,b)                IDirectSoundCaptureBuffer_Initialize(p,a,b)
+#define IDirectSoundCaptureBuffer8_Lock(p,a,b,c,d,e,f,g)            IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g)
+#define IDirectSoundCaptureBuffer8_Start(p,a)                       IDirectSoundCaptureBuffer_Start(p,a)
+#define IDirectSoundCaptureBuffer8_Stop(p)                          IDirectSoundCaptureBuffer_Stop(p))
+#define IDirectSoundCaptureBuffer8_Unlock(p,a,b,c,d)                IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d)       (p)->lpVtbl->GetObjectInPath(p,a,b,c,d)
+#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b)               (p)->lpVtbl->GetFXStatus(p,a,b)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d)       (p)->GetObjectInPath(a,b,c,d)
+#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b)               (p)->GetFXStatus(a,b)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSoundNotify
+//
+
+DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundNotify
+
+DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)           (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)            (THIS) PURE;
+    STDMETHOD_(ULONG,Release)           (THIS) PURE;
+
+    // IDirectSoundNotify methods
+    STDMETHOD(SetNotificationPositions) (THIS_ DWORD dwPositionNotifies, LPCDSBPOSITIONNOTIFY pcPositionNotifies) PURE;
+};
+
+#define IDirectSoundNotify_QueryInterface(p,a,b)            IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundNotify_AddRef(p)                        IUnknown_AddRef(p)
+#define IDirectSoundNotify_Release(p)                       IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundNotify_SetNotificationPositions(p,a,b)  (p)->lpVtbl->SetNotificationPositions(p,a,b)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundNotify_SetNotificationPositions(p,a,b)  (p)->SetNotificationPositions(a,b)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IKsPropertySet
+//
+
+#ifndef _IKsPropertySet_
+#define _IKsPropertySet_
+
+#ifdef __cplusplus
+// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined
+struct IKsPropertySet;
+#endif // __cplusplus
+
+typedef struct IKsPropertySet *LPKSPROPERTYSET;
+
+#define KSPROPERTY_SUPPORT_GET  0x00000001
+#define KSPROPERTY_SUPPORT_SET  0x00000002
+
+DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
+
+#undef INTERFACE
+#define INTERFACE IKsPropertySet
+
+DECLARE_INTERFACE_(IKsPropertySet, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)   (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)    (THIS) PURE;
+    STDMETHOD_(ULONG,Release)   (THIS) PURE;
+
+    // IKsPropertySet methods
+    STDMETHOD(Get)              (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength,
+                                       LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE;
+    STDMETHOD(Set)              (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength,
+                                       LPVOID pPropertyData, ULONG ulDataLength) PURE;
+    STDMETHOD(QuerySupport)     (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE;
+};
+
+#define IKsPropertySet_QueryInterface(p,a,b)       IUnknown_QueryInterface(p,a,b)
+#define IKsPropertySet_AddRef(p)                   IUnknown_AddRef(p)
+#define IKsPropertySet_Release(p)                  IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IKsPropertySet_Get(p,a,b,c,d,e,f,g)        (p)->lpVtbl->Get(p,a,b,c,d,e,f,g)
+#define IKsPropertySet_Set(p,a,b,c,d,e,f)          (p)->lpVtbl->Set(p,a,b,c,d,e,f)
+#define IKsPropertySet_QuerySupport(p,a,b,c)       (p)->lpVtbl->QuerySupport(p,a,b,c)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IKsPropertySet_Get(p,a,b,c,d,e,f,g)        (p)->Get(a,b,c,d,e,f,g)
+#define IKsPropertySet_Set(p,a,b,c,d,e,f)          (p)->Set(a,b,c,d,e,f)
+#define IKsPropertySet_QuerySupport(p,a,b,c)       (p)->QuerySupport(a,b,c)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // _IKsPropertySet_
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+//
+// IDirectSoundFXGargle
+//
+
+DEFINE_GUID(IID_IDirectSoundFXGargle, 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3);
+
+typedef struct _DSFXGargle
+{
+    DWORD       dwRateHz;               // Rate of modulation in hz
+    DWORD       dwWaveShape;            // DSFXGARGLE_WAVE_xxx
+} DSFXGargle, *LPDSFXGargle;
+
+#define DSFXGARGLE_WAVE_TRIANGLE        0
+#define DSFXGARGLE_WAVE_SQUARE          1
+
+typedef const DSFXGargle *LPCDSFXGargle;
+
+#define DSFXGARGLE_RATEHZ_MIN           1
+#define DSFXGARGLE_RATEHZ_MAX           1000
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXGargle
+
+DECLARE_INTERFACE_(IDirectSoundFXGargle, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXGargle methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXGargle pcDsFxGargle) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXGargle pDsFxGargle) PURE;
+};
+
+#define IDirectSoundFXGargle_QueryInterface(p,a,b)          IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXGargle_AddRef(p)                      IUnknown_AddRef(p)
+#define IDirectSoundFXGargle_Release(p)                     IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXGargle_SetAllParameters(p,a)          (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXGargle_GetAllParameters(p,a)          (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXGargle_SetAllParameters(p,a)          (p)->SetAllParameters(a)
+#define IDirectSoundFXGargle_GetAllParameters(p,a)          (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXChorus
+//
+
+DEFINE_GUID(IID_IDirectSoundFXChorus, 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47);
+
+typedef struct _DSFXChorus
+{
+    FLOAT       fWetDryMix;
+    FLOAT       fDepth;
+    FLOAT       fFeedback;
+    FLOAT       fFrequency;
+    LONG        lWaveform;          // LFO shape; DSFXCHORUS_WAVE_xxx
+    FLOAT       fDelay;
+    LONG        lPhase;
+} DSFXChorus, *LPDSFXChorus;
+
+typedef const DSFXChorus *LPCDSFXChorus;
+
+#define DSFXCHORUS_WAVE_TRIANGLE        0
+#define DSFXCHORUS_WAVE_SIN             1
+
+#define DSFXCHORUS_WETDRYMIX_MIN        0.0f
+#define DSFXCHORUS_WETDRYMIX_MAX        100.0f
+#define DSFXCHORUS_DEPTH_MIN            0.0f
+#define DSFXCHORUS_DEPTH_MAX            100.0f
+#define DSFXCHORUS_FEEDBACK_MIN         -99.0f
+#define DSFXCHORUS_FEEDBACK_MAX         99.0f
+#define DSFXCHORUS_FREQUENCY_MIN        0.0f
+#define DSFXCHORUS_FREQUENCY_MAX        10.0f
+#define DSFXCHORUS_DELAY_MIN            0.0f
+#define DSFXCHORUS_DELAY_MAX            20.0f
+#define DSFXCHORUS_PHASE_MIN            0
+#define DSFXCHORUS_PHASE_MAX            4
+
+#define DSFXCHORUS_PHASE_NEG_180        0
+#define DSFXCHORUS_PHASE_NEG_90         1
+#define DSFXCHORUS_PHASE_ZERO           2
+#define DSFXCHORUS_PHASE_90             3
+#define DSFXCHORUS_PHASE_180            4
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXChorus
+
+DECLARE_INTERFACE_(IDirectSoundFXChorus, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXChorus methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXChorus pcDsFxChorus) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXChorus pDsFxChorus) PURE;
+};
+
+#define IDirectSoundFXChorus_QueryInterface(p,a,b)          IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXChorus_AddRef(p)                      IUnknown_AddRef(p)
+#define IDirectSoundFXChorus_Release(p)                     IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXChorus_SetAllParameters(p,a)          (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXChorus_GetAllParameters(p,a)          (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXChorus_SetAllParameters(p,a)          (p)->SetAllParameters(a)
+#define IDirectSoundFXChorus_GetAllParameters(p,a)          (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXFlanger
+//
+
+DEFINE_GUID(IID_IDirectSoundFXFlanger, 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83);
+
+typedef struct _DSFXFlanger
+{
+    FLOAT       fWetDryMix;
+    FLOAT       fDepth;
+    FLOAT       fFeedback;
+    FLOAT       fFrequency;
+    LONG        lWaveform;
+    FLOAT       fDelay;
+    LONG        lPhase;
+} DSFXFlanger, *LPDSFXFlanger;
+
+typedef const DSFXFlanger *LPCDSFXFlanger;
+
+#define DSFXFLANGER_WAVE_TRIANGLE       0
+#define DSFXFLANGER_WAVE_SIN            1
+
+#define DSFXFLANGER_WETDRYMIX_MIN       0.0f
+#define DSFXFLANGER_WETDRYMIX_MAX       100.0f
+#define DSFXFLANGER_FREQUENCY_MIN       0.0f
+#define DSFXFLANGER_FREQUENCY_MAX       10.0f
+#define DSFXFLANGER_DEPTH_MIN           0.0f
+#define DSFXFLANGER_DEPTH_MAX           100.0f
+#define DSFXFLANGER_PHASE_MIN           0
+#define DSFXFLANGER_PHASE_MAX           4
+#define DSFXFLANGER_FEEDBACK_MIN        -99.0f
+#define DSFXFLANGER_FEEDBACK_MAX        99.0f
+#define DSFXFLANGER_DELAY_MIN           0.0f
+#define DSFXFLANGER_DELAY_MAX           4.0f
+
+#define DSFXFLANGER_PHASE_NEG_180       0
+#define DSFXFLANGER_PHASE_NEG_90        1
+#define DSFXFLANGER_PHASE_ZERO          2
+#define DSFXFLANGER_PHASE_90            3
+#define DSFXFLANGER_PHASE_180           4
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXFlanger
+
+DECLARE_INTERFACE_(IDirectSoundFXFlanger, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXFlanger methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXFlanger pcDsFxFlanger) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXFlanger pDsFxFlanger) PURE;
+};
+
+#define IDirectSoundFXFlanger_QueryInterface(p,a,b)         IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXFlanger_AddRef(p)                     IUnknown_AddRef(p)
+#define IDirectSoundFXFlanger_Release(p)                    IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXFlanger_SetAllParameters(p,a)         (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXFlanger_GetAllParameters(p,a)         (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXFlanger_SetAllParameters(p,a)         (p)->SetAllParameters(a)
+#define IDirectSoundFXFlanger_GetAllParameters(p,a)         (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXEcho
+//
+
+DEFINE_GUID(IID_IDirectSoundFXEcho, 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42);
+
+typedef struct _DSFXEcho
+{
+    FLOAT   fWetDryMix;
+    FLOAT   fFeedback;
+    FLOAT   fLeftDelay;
+    FLOAT   fRightDelay;
+    LONG    lPanDelay;
+} DSFXEcho, *LPDSFXEcho;
+
+typedef const DSFXEcho *LPCDSFXEcho;
+
+#define DSFXECHO_WETDRYMIX_MIN      0.0f
+#define DSFXECHO_WETDRYMIX_MAX      100.0f
+#define DSFXECHO_FEEDBACK_MIN       0.0f
+#define DSFXECHO_FEEDBACK_MAX       100.0f
+#define DSFXECHO_LEFTDELAY_MIN      1.0f
+#define DSFXECHO_LEFTDELAY_MAX      2000.0f
+#define DSFXECHO_RIGHTDELAY_MIN     1.0f
+#define DSFXECHO_RIGHTDELAY_MAX     2000.0f
+#define DSFXECHO_PANDELAY_MIN       0
+#define DSFXECHO_PANDELAY_MAX       1
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXEcho
+
+DECLARE_INTERFACE_(IDirectSoundFXEcho, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXEcho methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXEcho pcDsFxEcho) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXEcho pDsFxEcho) PURE;
+};
+
+#define IDirectSoundFXEcho_QueryInterface(p,a,b)            IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXEcho_AddRef(p)                        IUnknown_AddRef(p)
+#define IDirectSoundFXEcho_Release(p)                       IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXEcho_SetAllParameters(p,a)            (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXEcho_GetAllParameters(p,a)            (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXEcho_SetAllParameters(p,a)            (p)->SetAllParameters(a)
+#define IDirectSoundFXEcho_GetAllParameters(p,a)            (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXDistortion
+//
+
+DEFINE_GUID(IID_IDirectSoundFXDistortion, 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b);
+
+typedef struct _DSFXDistortion
+{
+    FLOAT   fGain;
+    FLOAT   fEdge;
+    FLOAT   fPostEQCenterFrequency;
+    FLOAT   fPostEQBandwidth;
+    FLOAT   fPreLowpassCutoff;
+} DSFXDistortion, *LPDSFXDistortion;
+
+typedef const DSFXDistortion *LPCDSFXDistortion;
+
+#define DSFXDISTORTION_GAIN_MIN                     -60.0f
+#define DSFXDISTORTION_GAIN_MAX                     0.0f
+#define DSFXDISTORTION_EDGE_MIN                     0.0f
+#define DSFXDISTORTION_EDGE_MAX                     100.0f
+#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN    100.0f
+#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX    8000.0f
+#define DSFXDISTORTION_POSTEQBANDWIDTH_MIN          100.0f
+#define DSFXDISTORTION_POSTEQBANDWIDTH_MAX          8000.0f
+#define DSFXDISTORTION_PRELOWPASSCUTOFF_MIN         100.0f
+#define DSFXDISTORTION_PRELOWPASSCUTOFF_MAX         8000.0f
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXDistortion
+
+DECLARE_INTERFACE_(IDirectSoundFXDistortion, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXDistortion methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXDistortion pcDsFxDistortion) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXDistortion pDsFxDistortion) PURE;
+};
+
+#define IDirectSoundFXDistortion_QueryInterface(p,a,b)      IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXDistortion_AddRef(p)                  IUnknown_AddRef(p)
+#define IDirectSoundFXDistortion_Release(p)                 IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXDistortion_SetAllParameters(p,a)      (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXDistortion_GetAllParameters(p,a)      (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXDistortion_SetAllParameters(p,a)      (p)->SetAllParameters(a)
+#define IDirectSoundFXDistortion_GetAllParameters(p,a)      (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXCompressor
+//
+
+DEFINE_GUID(IID_IDirectSoundFXCompressor, 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0);
+
+typedef struct _DSFXCompressor
+{
+    FLOAT   fGain;
+    FLOAT   fAttack;
+    FLOAT   fRelease;
+    FLOAT   fThreshold;
+    FLOAT   fRatio;
+    FLOAT   fPredelay;
+} DSFXCompressor, *LPDSFXCompressor;
+
+typedef const DSFXCompressor *LPCDSFXCompressor;
+
+#define DSFXCOMPRESSOR_GAIN_MIN             -60.0f
+#define DSFXCOMPRESSOR_GAIN_MAX             60.0f
+#define DSFXCOMPRESSOR_ATTACK_MIN           0.01f
+#define DSFXCOMPRESSOR_ATTACK_MAX           500.0f
+#define DSFXCOMPRESSOR_RELEASE_MIN          50.0f
+#define DSFXCOMPRESSOR_RELEASE_MAX          3000.0f
+#define DSFXCOMPRESSOR_THRESHOLD_MIN        -60.0f
+#define DSFXCOMPRESSOR_THRESHOLD_MAX        0.0f
+#define DSFXCOMPRESSOR_RATIO_MIN            1.0f
+#define DSFXCOMPRESSOR_RATIO_MAX            100.0f
+#define DSFXCOMPRESSOR_PREDELAY_MIN         0.0f
+#define DSFXCOMPRESSOR_PREDELAY_MAX         4.0f
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXCompressor
+
+DECLARE_INTERFACE_(IDirectSoundFXCompressor, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXCompressor methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXCompressor pcDsFxCompressor) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXCompressor pDsFxCompressor) PURE;
+};
+
+#define IDirectSoundFXCompressor_QueryInterface(p,a,b)      IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXCompressor_AddRef(p)                  IUnknown_AddRef(p)
+#define IDirectSoundFXCompressor_Release(p)                 IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXCompressor_SetAllParameters(p,a)      (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXCompressor_GetAllParameters(p,a)      (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXCompressor_SetAllParameters(p,a)      (p)->SetAllParameters(a)
+#define IDirectSoundFXCompressor_GetAllParameters(p,a)      (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXParamEq
+//
+
+DEFINE_GUID(IID_IDirectSoundFXParamEq, 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda);
+
+typedef struct _DSFXParamEq
+{
+    FLOAT   fCenter;
+    FLOAT   fBandwidth;
+    FLOAT   fGain;
+} DSFXParamEq, *LPDSFXParamEq;
+
+typedef const DSFXParamEq *LPCDSFXParamEq;
+
+#define DSFXPARAMEQ_CENTER_MIN      80.0f
+#define DSFXPARAMEQ_CENTER_MAX      16000.0f
+#define DSFXPARAMEQ_BANDWIDTH_MIN   1.0f
+#define DSFXPARAMEQ_BANDWIDTH_MAX   36.0f
+#define DSFXPARAMEQ_GAIN_MIN        -15.0f
+#define DSFXPARAMEQ_GAIN_MAX        15.0f
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXParamEq
+
+DECLARE_INTERFACE_(IDirectSoundFXParamEq, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXParamEq methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXParamEq pcDsFxParamEq) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXParamEq pDsFxParamEq) PURE;
+};
+
+#define IDirectSoundFXParamEq_QueryInterface(p,a,b)      IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXParamEq_AddRef(p)                  IUnknown_AddRef(p)
+#define IDirectSoundFXParamEq_Release(p)                 IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXParamEq_SetAllParameters(p,a)      (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXParamEq_GetAllParameters(p,a)      (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXParamEq_SetAllParameters(p,a)      (p)->SetAllParameters(a)
+#define IDirectSoundFXParamEq_GetAllParameters(p,a)      (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXI3DL2Reverb
+//
+
+DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4);
+
+typedef struct _DSFXI3DL2Reverb
+{
+    LONG    lRoom;                  // [-10000, 0]      default: -1000 mB
+    LONG    lRoomHF;                // [-10000, 0]      default: 0 mB
+    FLOAT   flRoomRolloffFactor;    // [0.0, 10.0]      default: 0.0
+    FLOAT   flDecayTime;            // [0.1, 20.0]      default: 1.49s
+    FLOAT   flDecayHFRatio;         // [0.1, 2.0]       default: 0.83
+    LONG    lReflections;           // [-10000, 1000]   default: -2602 mB
+    FLOAT   flReflectionsDelay;     // [0.0, 0.3]       default: 0.007 s
+    LONG    lReverb;                // [-10000, 2000]   default: 200 mB
+    FLOAT   flReverbDelay;          // [0.0, 0.1]       default: 0.011 s
+    FLOAT   flDiffusion;            // [0.0, 100.0]     default: 100.0 %
+    FLOAT   flDensity;              // [0.0, 100.0]     default: 100.0 %
+    FLOAT   flHFReference;          // [20.0, 20000.0]  default: 5000.0 Hz
+} DSFXI3DL2Reverb, *LPDSFXI3DL2Reverb;
+
+typedef const DSFXI3DL2Reverb *LPCDSFXI3DL2Reverb;
+
+#define DSFX_I3DL2REVERB_ROOM_MIN                   (-10000)
+#define DSFX_I3DL2REVERB_ROOM_MAX                   0
+#define DSFX_I3DL2REVERB_ROOM_DEFAULT               (-1000)
+
+#define DSFX_I3DL2REVERB_ROOMHF_MIN                 (-10000)
+#define DSFX_I3DL2REVERB_ROOMHF_MAX                 0
+#define DSFX_I3DL2REVERB_ROOMHF_DEFAULT             (-100)
+
+#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN      0.0f
+#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX      10.0f
+#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT  0.0f
+
+#define DSFX_I3DL2REVERB_DECAYTIME_MIN              0.1f
+#define DSFX_I3DL2REVERB_DECAYTIME_MAX              20.0f
+#define DSFX_I3DL2REVERB_DECAYTIME_DEFAULT          1.49f
+
+#define DSFX_I3DL2REVERB_DECAYHFRATIO_MIN           0.1f
+#define DSFX_I3DL2REVERB_DECAYHFRATIO_MAX           2.0f
+#define DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT       0.83f
+
+#define DSFX_I3DL2REVERB_REFLECTIONS_MIN            (-10000)
+#define DSFX_I3DL2REVERB_REFLECTIONS_MAX            1000
+#define DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT        (-2602)
+
+#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN       0.0f
+#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX       0.3f
+#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT   0.007f
+
+#define DSFX_I3DL2REVERB_REVERB_MIN                 (-10000)
+#define DSFX_I3DL2REVERB_REVERB_MAX                 2000
+#define DSFX_I3DL2REVERB_REVERB_DEFAULT             (200)
+
+#define DSFX_I3DL2REVERB_REVERBDELAY_MIN            0.0f
+#define DSFX_I3DL2REVERB_REVERBDELAY_MAX            0.1f
+#define DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT        0.011f
+
+#define DSFX_I3DL2REVERB_DIFFUSION_MIN              0.0f
+#define DSFX_I3DL2REVERB_DIFFUSION_MAX              100.0f
+#define DSFX_I3DL2REVERB_DIFFUSION_DEFAULT          100.0f
+
+#define DSFX_I3DL2REVERB_DENSITY_MIN                0.0f
+#define DSFX_I3DL2REVERB_DENSITY_MAX                100.0f
+#define DSFX_I3DL2REVERB_DENSITY_DEFAULT            100.0f
+
+#define DSFX_I3DL2REVERB_HFREFERENCE_MIN            20.0f
+#define DSFX_I3DL2REVERB_HFREFERENCE_MAX            20000.0f
+#define DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT        5000.0f
+
+#define DSFX_I3DL2REVERB_QUALITY_MIN                0
+#define DSFX_I3DL2REVERB_QUALITY_MAX                3
+#define DSFX_I3DL2REVERB_QUALITY_DEFAULT            2
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXI3DL2Reverb
+
+DECLARE_INTERFACE_(IDirectSoundFXI3DL2Reverb, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXI3DL2Reverb methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXI3DL2Reverb pcDsFxI3DL2Reverb) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXI3DL2Reverb pDsFxI3DL2Reverb) PURE;
+    STDMETHOD(SetPreset)            (THIS_ DWORD dwPreset) PURE;
+    STDMETHOD(GetPreset)            (THIS_ LPDWORD pdwPreset) PURE;
+    STDMETHOD(SetQuality)           (THIS_ LONG lQuality) PURE;
+    STDMETHOD(GetQuality)           (THIS_ LONG *plQuality) PURE;
+};
+
+#define IDirectSoundFXI3DL2Reverb_QueryInterface(p,a,b)     IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXI3DL2Reverb_AddRef(p)                 IUnknown_AddRef(p)
+#define IDirectSoundFXI3DL2Reverb_Release(p)                IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a)     (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a)     (p)->lpVtbl->GetAllParameters(p,a)
+#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a)            (p)->lpVtbl->SetPreset(p,a)
+#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a)            (p)->lpVtbl->GetPreset(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a)     (p)->SetAllParameters(a)
+#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a)     (p)->GetAllParameters(a)
+#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a)            (p)->SetPreset(a)
+#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a)            (p)->GetPreset(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundFXWavesReverb
+//
+
+DEFINE_GUID(IID_IDirectSoundFXWavesReverb,0x46858c3a,0x0dc6,0x45e3,0xb7,0x60,0xd4,0xee,0xf1,0x6c,0xb3,0x25);
+
+typedef struct _DSFXWavesReverb
+{
+    FLOAT   fInGain;                // [-96.0,0.0]            default: 0.0 dB
+    FLOAT   fReverbMix;             // [-96.0,0.0]            default: 0.0 db
+    FLOAT   fReverbTime;            // [0.001,3000.0]         default: 1000.0 ms
+    FLOAT   fHighFreqRTRatio;       // [0.001,0.999]          default: 0.001
+} DSFXWavesReverb, *LPDSFXWavesReverb;
+
+typedef const DSFXWavesReverb *LPCDSFXWavesReverb;
+
+#define DSFX_WAVESREVERB_INGAIN_MIN                 -96.0f
+#define DSFX_WAVESREVERB_INGAIN_MAX                 0.0f
+#define DSFX_WAVESREVERB_INGAIN_DEFAULT             0.0f
+#define DSFX_WAVESREVERB_REVERBMIX_MIN              -96.0f
+#define DSFX_WAVESREVERB_REVERBMIX_MAX              0.0f
+#define DSFX_WAVESREVERB_REVERBMIX_DEFAULT          0.0f
+#define DSFX_WAVESREVERB_REVERBTIME_MIN             0.001f
+#define DSFX_WAVESREVERB_REVERBTIME_MAX             3000.0f
+#define DSFX_WAVESREVERB_REVERBTIME_DEFAULT         1000.0f
+#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN        0.001f
+#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX        0.999f
+#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT    0.001f
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFXWavesReverb
+
+DECLARE_INTERFACE_(IDirectSoundFXWavesReverb, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundFXWavesReverb methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSFXWavesReverb pcDsFxWavesReverb) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSFXWavesReverb pDsFxWavesReverb) PURE;
+};
+
+#define IDirectSoundFXWavesReverb_QueryInterface(p,a,b)     IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFXWavesReverb_AddRef(p)                 IUnknown_AddRef(p)
+#define IDirectSoundFXWavesReverb_Release(p)                IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXWavesReverb_SetAllParameters(p,a)     (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundFXWavesReverb_GetAllParameters(p,a)     (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFXWavesReverb_SetAllParameters(p,a)     (p)->SetAllParameters(a)
+#define IDirectSoundFXWavesReverb_GetAllParameters(p,a)     (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+//
+// IDirectSoundCaptureFXAec
+//
+
+DEFINE_GUID(IID_IDirectSoundCaptureFXAec, 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65);
+
+typedef struct _DSCFXAec
+{
+    BOOL    fEnable;
+    BOOL    fNoiseFill;
+    DWORD   dwMode;
+} DSCFXAec, *LPDSCFXAec;
+
+typedef const DSCFXAec *LPCDSCFXAec;
+
+// These match the AEC_MODE_* constants in the DDK's ksmedia.h file
+#define DSCFX_AEC_MODE_PASS_THROUGH                     0x0
+#define DSCFX_AEC_MODE_HALF_DUPLEX                      0x1
+#define DSCFX_AEC_MODE_FULL_DUPLEX                      0x2
+
+// These match the AEC_STATUS_* constants in ksmedia.h
+#define DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED          0x0
+#define DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED 0x1
+#define DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED    0x2
+#define DSCFX_AEC_STATUS_CURRENTLY_CONVERGED            0x8
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundCaptureFXAec
+
+DECLARE_INTERFACE_(IDirectSoundCaptureFXAec, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundCaptureFXAec methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSCFXAec pDscFxAec) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSCFXAec pDscFxAec) PURE;
+    STDMETHOD(GetStatus)            (THIS_ PDWORD pdwStatus) PURE;
+    STDMETHOD(Reset)                (THIS) PURE;
+};
+
+#define IDirectSoundCaptureFXAec_QueryInterface(p,a,b)     IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundCaptureFXAec_AddRef(p)                 IUnknown_AddRef(p)
+#define IDirectSoundCaptureFXAec_Release(p)                IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureFXAec_SetAllParameters(p,a)     (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundCaptureFXAec_GetAllParameters(p,a)     (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureFXAec_SetAllParameters(p,a)     (p)->SetAllParameters(a)
+#define IDirectSoundCaptureFXAec_GetAllParameters(p,a)     (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+
+//
+// IDirectSoundCaptureFXNoiseSuppress
+//
+
+DEFINE_GUID(IID_IDirectSoundCaptureFXNoiseSuppress, 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x8, 0x54, 0xf6, 0x93, 0xca);
+
+typedef struct _DSCFXNoiseSuppress
+{
+    BOOL    fEnable;
+} DSCFXNoiseSuppress, *LPDSCFXNoiseSuppress;
+
+typedef const DSCFXNoiseSuppress *LPCDSCFXNoiseSuppress;
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundCaptureFXNoiseSuppress
+
+DECLARE_INTERFACE_(IDirectSoundCaptureFXNoiseSuppress, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
+    STDMETHOD_(ULONG,Release)       (THIS) PURE;
+
+    // IDirectSoundCaptureFXNoiseSuppress methods
+    STDMETHOD(SetAllParameters)     (THIS_ LPCDSCFXNoiseSuppress pcDscFxNoiseSuppress) PURE;
+    STDMETHOD(GetAllParameters)     (THIS_ LPDSCFXNoiseSuppress pDscFxNoiseSuppress) PURE;
+    STDMETHOD(Reset)                (THIS) PURE;
+};
+
+#define IDirectSoundCaptureFXNoiseSuppress_QueryInterface(p,a,b)     IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundCaptureFXNoiseSuppress_AddRef(p)                 IUnknown_AddRef(p)
+#define IDirectSoundCaptureFXNoiseSuppress_Release(p)                IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a)     (p)->lpVtbl->SetAllParameters(p,a)
+#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a)     (p)->lpVtbl->GetAllParameters(p,a)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a)     (p)->SetAllParameters(a)
+#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a)     (p)->GetAllParameters(a)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+
+//
+// IDirectSoundFullDuplex
+//
+
+#ifndef _IDirectSoundFullDuplex_
+#define _IDirectSoundFullDuplex_
+
+#ifdef __cplusplus
+// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined
+struct IDirectSoundFullDuplex;
+#endif // __cplusplus
+
+typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX;
+
+DEFINE_GUID(IID_IDirectSoundFullDuplex, 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d);
+
+#undef INTERFACE
+#define INTERFACE IDirectSoundFullDuplex
+
+DECLARE_INTERFACE_(IDirectSoundFullDuplex, IUnknown)
+{
+    // IUnknown methods
+    STDMETHOD(QueryInterface)   (THIS_ REFIID, LPVOID *) PURE;
+    STDMETHOD_(ULONG,AddRef)    (THIS) PURE;
+    STDMETHOD_(ULONG,Release)   (THIS) PURE;
+
+    // IDirectSoundFullDuplex methods
+    STDMETHOD(Initialize)     (THIS_ LPCGUID pCaptureGuid, LPCGUID pRenderGuid, LPCDSCBUFFERDESC lpDscBufferDesc, LPCDSBUFFERDESC lpDsBufferDesc, HWND hWnd, DWORD dwLevel, LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8) PURE;
+};
+
+#define IDirectSoundFullDuplex_QueryInterface(p,a,b)    IUnknown_QueryInterface(p,a,b)
+#define IDirectSoundFullDuplex_AddRef(p)                IUnknown_AddRef(p)
+#define IDirectSoundFullDuplex_Release(p)               IUnknown_Release(p)
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h)     (p)->lpVtbl->Initialize(p,a,b,c,d,e,f,g,h)
+#else // !defined(__cplusplus) || defined(CINTERFACE)
+#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h)     (p)->Initialize(a,b,c,d,e,f,g,h)
+#endif // !defined(__cplusplus) || defined(CINTERFACE)
+
+#endif // _IDirectSoundFullDuplex_
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+//
+// Return Codes
+//
+
+// The function completed successfully
+#define DS_OK                           S_OK
+
+// The call succeeded, but we had to substitute the 3D algorithm
+#define DS_NO_VIRTUALIZATION            MAKE_HRESULT(0, _FACDS, 10)
+
+// The call failed because resources (such as a priority level)
+// were already being used by another caller
+#define DSERR_ALLOCATED                 MAKE_DSHRESULT(10)
+
+// The control (vol, pan, etc.) requested by the caller is not available
+#define DSERR_CONTROLUNAVAIL            MAKE_DSHRESULT(30)
+
+// An invalid parameter was passed to the returning function
+#define DSERR_INVALIDPARAM              E_INVALIDARG
+
+// This call is not valid for the current state of this object
+#define DSERR_INVALIDCALL               MAKE_DSHRESULT(50)
+
+// An undetermined error occurred inside the DirectSound subsystem
+#define DSERR_GENERIC                   E_FAIL
+
+// The caller does not have the priority level required for the function to
+// succeed
+#define DSERR_PRIOLEVELNEEDED           MAKE_DSHRESULT(70)
+
+// Not enough free memory is available to complete the operation
+#define DSERR_OUTOFMEMORY               E_OUTOFMEMORY
+
+// The specified WAVE format is not supported
+#define DSERR_BADFORMAT                 MAKE_DSHRESULT(100)
+
+// The function called is not supported at this time
+#define DSERR_UNSUPPORTED               E_NOTIMPL
+
+// No sound driver is available for use
+#define DSERR_NODRIVER                  MAKE_DSHRESULT(120)
+// This object is already initialized
+#define DSERR_ALREADYINITIALIZED        MAKE_DSHRESULT(130)
+
+// This object does not support aggregation
+#define DSERR_NOAGGREGATION             CLASS_E_NOAGGREGATION
+
+// The buffer memory has been lost, and must be restored
+#define DSERR_BUFFERLOST                MAKE_DSHRESULT(150)
+
+// Another app has a higher priority level, preventing this call from
+// succeeding
+#define DSERR_OTHERAPPHASPRIO           MAKE_DSHRESULT(160)
+
+// This object has not been initialized
+#define DSERR_UNINITIALIZED             MAKE_DSHRESULT(170)
+
+// The requested COM interface is not available
+#define DSERR_NOINTERFACE               E_NOINTERFACE
+
+// Access is denied
+#define DSERR_ACCESSDENIED              E_ACCESSDENIED
+
+// Tried to create a DSBCAPS_CTRLFX buffer shorter than DSBSIZE_FX_MIN milliseconds
+#define DSERR_BUFFERTOOSMALL            MAKE_DSHRESULT(180)
+
+// Attempt to use DirectSound 8 functionality on an older DirectSound object
+#define DSERR_DS8_REQUIRED              MAKE_DSHRESULT(190)
+
+// A circular loop of send effects was detected
+#define DSERR_SENDLOOP                  MAKE_DSHRESULT(200)
+
+// The GUID specified in an audiopath file does not match a valid MIXIN buffer
+#define DSERR_BADSENDBUFFERGUID         MAKE_DSHRESULT(210)
+
+// The object requested was not found (numerically equal to DMUS_E_NOT_FOUND)
+#define DSERR_OBJECTNOTFOUND            MAKE_DSHRESULT(4449)
+
+// The effects requested could not be found on the system, or they were found
+// but in the wrong order, or in the wrong hardware/software locations.
+#define DSERR_FXUNAVAILABLE             MAKE_DSHRESULT(220)
+
+//
+// Flags
+//
+
+#define DSCAPS_PRIMARYMONO          0x00000001
+#define DSCAPS_PRIMARYSTEREO        0x00000002
+#define DSCAPS_PRIMARY8BIT          0x00000004
+#define DSCAPS_PRIMARY16BIT         0x00000008
+#define DSCAPS_CONTINUOUSRATE       0x00000010
+#define DSCAPS_EMULDRIVER           0x00000020
+#define DSCAPS_CERTIFIED            0x00000040
+#define DSCAPS_SECONDARYMONO        0x00000100
+#define DSCAPS_SECONDARYSTEREO      0x00000200
+#define DSCAPS_SECONDARY8BIT        0x00000400
+#define DSCAPS_SECONDARY16BIT       0x00000800
+
+#define DSSCL_NORMAL                0x00000001
+#define DSSCL_PRIORITY              0x00000002
+#define DSSCL_EXCLUSIVE             0x00000003
+#define DSSCL_WRITEPRIMARY          0x00000004
+
+#define DSSPEAKER_DIRECTOUT         0x00000000
+#define DSSPEAKER_HEADPHONE         0x00000001
+#define DSSPEAKER_MONO              0x00000002
+#define DSSPEAKER_QUAD              0x00000003
+#define DSSPEAKER_STEREO            0x00000004
+#define DSSPEAKER_SURROUND          0x00000005
+#define DSSPEAKER_5POINT1           0x00000006  // obsolete 5.1 setting
+#define DSSPEAKER_7POINT1           0x00000007  // obsolete 7.1 setting
+#define DSSPEAKER_7POINT1_SURROUND  0x00000008  // correct 7.1 Home Theater setting
+#define DSSPEAKER_7POINT1_WIDE      DSSPEAKER_7POINT1
+#if (DIRECTSOUND_VERSION >= 0x1000)
+    #define DSSPEAKER_5POINT1_SURROUND  0x00000009  // correct 5.1 setting
+    #define DSSPEAKER_5POINT1_BACK      DSSPEAKER_5POINT1
+#endif
+
+#define DSSPEAKER_GEOMETRY_MIN      0x00000005  //   5 degrees
+#define DSSPEAKER_GEOMETRY_NARROW   0x0000000A  //  10 degrees
+#define DSSPEAKER_GEOMETRY_WIDE     0x00000014  //  20 degrees
+#define DSSPEAKER_GEOMETRY_MAX      0x000000B4  // 180 degrees
+
+#define DSSPEAKER_COMBINED(c, g)    ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16))
+#define DSSPEAKER_CONFIG(a)         ((BYTE)(a))
+#define DSSPEAKER_GEOMETRY(a)       ((BYTE)(((DWORD)(a) >> 16) & 0x00FF))
+
+#define DSBCAPS_PRIMARYBUFFER       0x00000001
+#define DSBCAPS_STATIC              0x00000002
+#define DSBCAPS_LOCHARDWARE         0x00000004
+#define DSBCAPS_LOCSOFTWARE         0x00000008
+#define DSBCAPS_CTRL3D              0x00000010
+#define DSBCAPS_CTRLFREQUENCY       0x00000020
+#define DSBCAPS_CTRLPAN             0x00000040
+#define DSBCAPS_CTRLVOLUME          0x00000080
+#define DSBCAPS_CTRLPOSITIONNOTIFY  0x00000100
+#define DSBCAPS_CTRLFX              0x00000200
+#define DSBCAPS_STICKYFOCUS         0x00004000
+#define DSBCAPS_GLOBALFOCUS         0x00008000
+#define DSBCAPS_GETCURRENTPOSITION2 0x00010000
+#define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000
+#define DSBCAPS_LOCDEFER            0x00040000
+#if (DIRECTSOUND_VERSION >= 0x1000)
+    // Force GetCurrentPosition() to return a buffer's true play position;
+    // unmodified by aids to enhance backward compatibility.
+    #define DSBCAPS_TRUEPLAYPOSITION    0x00080000
+#endif
+
+#define DSBPLAY_LOOPING             0x00000001
+#define DSBPLAY_LOCHARDWARE         0x00000002
+#define DSBPLAY_LOCSOFTWARE         0x00000004
+#define DSBPLAY_TERMINATEBY_TIME    0x00000008
+#define DSBPLAY_TERMINATEBY_DISTANCE    0x000000010
+#define DSBPLAY_TERMINATEBY_PRIORITY    0x000000020
+
+#define DSBSTATUS_PLAYING           0x00000001
+#define DSBSTATUS_BUFFERLOST        0x00000002
+#define DSBSTATUS_LOOPING           0x00000004
+#define DSBSTATUS_LOCHARDWARE       0x00000008
+#define DSBSTATUS_LOCSOFTWARE       0x00000010
+#define DSBSTATUS_TERMINATED        0x00000020
+
+#define DSBLOCK_FROMWRITECURSOR     0x00000001
+#define DSBLOCK_ENTIREBUFFER        0x00000002
+
+#define DSBFREQUENCY_ORIGINAL       0
+#define DSBFREQUENCY_MIN            100
+#if DIRECTSOUND_VERSION >= 0x0900
+#define DSBFREQUENCY_MAX            200000
+#else
+#define DSBFREQUENCY_MAX            100000
+#endif
+
+#define DSBPAN_LEFT                 -10000
+#define DSBPAN_CENTER               0
+#define DSBPAN_RIGHT                10000
+
+#define DSBVOLUME_MIN               -10000
+#define DSBVOLUME_MAX               0
+
+#define DSBSIZE_MIN                 4
+#define DSBSIZE_MAX                 0x0FFFFFFF
+#define DSBSIZE_FX_MIN              150  // NOTE: Milliseconds, not bytes
+
+#define DSBNOTIFICATIONS_MAX        100000UL
+
+#define DS3DMODE_NORMAL             0x00000000
+#define DS3DMODE_HEADRELATIVE       0x00000001
+#define DS3DMODE_DISABLE            0x00000002
+
+#define DS3D_IMMEDIATE              0x00000000
+#define DS3D_DEFERRED               0x00000001
+
+#define DS3D_MINDISTANCEFACTOR      FLT_MIN
+#define DS3D_MAXDISTANCEFACTOR      FLT_MAX
+#define DS3D_DEFAULTDISTANCEFACTOR  1.0f
+
+#define DS3D_MINROLLOFFFACTOR       0.0f
+#define DS3D_MAXROLLOFFFACTOR       10.0f
+#define DS3D_DEFAULTROLLOFFFACTOR   1.0f
+
+#define DS3D_MINDOPPLERFACTOR       0.0f
+#define DS3D_MAXDOPPLERFACTOR       10.0f
+#define DS3D_DEFAULTDOPPLERFACTOR   1.0f
+
+#define DS3D_DEFAULTMINDISTANCE     1.0f
+#define DS3D_DEFAULTMAXDISTANCE     1000000000.0f
+
+#define DS3D_MINCONEANGLE           0
+#define DS3D_MAXCONEANGLE           360
+#define DS3D_DEFAULTCONEANGLE       360
+
+#define DS3D_DEFAULTCONEOUTSIDEVOLUME DSBVOLUME_MAX
+
+// IDirectSoundCapture attributes
+
+#define DSCCAPS_EMULDRIVER          DSCAPS_EMULDRIVER
+#define DSCCAPS_CERTIFIED           DSCAPS_CERTIFIED
+#define DSCCAPS_MULTIPLECAPTURE     0x00000001
+
+// IDirectSoundCaptureBuffer attributes
+
+#define DSCBCAPS_WAVEMAPPED         0x80000000
+
+#if DIRECTSOUND_VERSION >= 0x0800
+#define DSCBCAPS_CTRLFX             0x00000200
+#endif
+
+
+#define DSCBLOCK_ENTIREBUFFER       0x00000001
+
+#define DSCBSTATUS_CAPTURING        0x00000001
+#define DSCBSTATUS_LOOPING          0x00000002
+
+#define DSCBSTART_LOOPING           0x00000001
+
+#define DSBPN_OFFSETSTOP            0xFFFFFFFF
+
+#define DS_CERTIFIED                0x00000000
+#define DS_UNCERTIFIED              0x00000001
+
+
+//
+// Flags for the I3DL2 effects
+//
+
+//
+// I3DL2 Material Presets
+//
+
+enum
+{
+    DSFX_I3DL2_MATERIAL_PRESET_SINGLEWINDOW,
+    DSFX_I3DL2_MATERIAL_PRESET_DOUBLEWINDOW,
+    DSFX_I3DL2_MATERIAL_PRESET_THINDOOR,
+    DSFX_I3DL2_MATERIAL_PRESET_THICKDOOR,
+    DSFX_I3DL2_MATERIAL_PRESET_WOODWALL,
+    DSFX_I3DL2_MATERIAL_PRESET_BRICKWALL,
+    DSFX_I3DL2_MATERIAL_PRESET_STONEWALL,
+    DSFX_I3DL2_MATERIAL_PRESET_CURTAIN
+};
+
+#define I3DL2_MATERIAL_PRESET_SINGLEWINDOW    -2800,0.71f
+#define I3DL2_MATERIAL_PRESET_DOUBLEWINDOW    -5000,0.40f
+#define I3DL2_MATERIAL_PRESET_THINDOOR        -1800,0.66f
+#define I3DL2_MATERIAL_PRESET_THICKDOOR       -4400,0.64f
+#define I3DL2_MATERIAL_PRESET_WOODWALL        -4000,0.50f
+#define I3DL2_MATERIAL_PRESET_BRICKWALL       -5000,0.60f
+#define I3DL2_MATERIAL_PRESET_STONEWALL       -6000,0.68f
+#define I3DL2_MATERIAL_PRESET_CURTAIN         -1200,0.15f
+
+enum
+{
+    DSFX_I3DL2_ENVIRONMENT_PRESET_DEFAULT,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_GENERIC,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_PADDEDCELL,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_ROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_BATHROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_LIVINGROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_STONEROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_AUDITORIUM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_CONCERTHALL,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_CAVE,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_ARENA,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_HANGAR,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_HALLWAY,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_ALLEY,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_FOREST,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_CITY,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_MOUNTAINS,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_QUARRY,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_PLAIN,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_PARKINGLOT,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_SEWERPIPE,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_UNDERWATER,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_SMALLROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEROOM,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEHALL,
+    DSFX_I3DL2_ENVIRONMENT_PRESET_PLATE
+};
+
+//
+// I3DL2 Reverberation Presets Values
+//
+
+#define I3DL2_ENVIRONMENT_PRESET_DEFAULT         -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f,   200, 0.011f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_GENERIC         -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f,   200, 0.011f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_PADDEDCELL      -1000,-6000, 0.0f, 0.17f, 0.10f, -1204, 0.001f,   207, 0.002f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_ROOM            -1000, -454, 0.0f, 0.40f, 0.83f, -1646, 0.002f,    53, 0.003f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_BATHROOM        -1000,-1200, 0.0f, 1.49f, 0.54f,  -370, 0.007f,  1030, 0.011f, 100.0f,  60.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_LIVINGROOM      -1000,-6000, 0.0f, 0.50f, 0.10f, -1376, 0.003f, -1104, 0.004f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_STONEROOM       -1000, -300, 0.0f, 2.31f, 0.64f,  -711, 0.012f,    83, 0.017f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_AUDITORIUM      -1000, -476, 0.0f, 4.32f, 0.59f,  -789, 0.020f,  -289, 0.030f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_CONCERTHALL     -1000, -500, 0.0f, 3.92f, 0.70f, -1230, 0.020f,    -2, 0.029f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_CAVE            -1000,    0, 0.0f, 2.91f, 1.30f,  -602, 0.015f,  -302, 0.022f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_ARENA           -1000, -698, 0.0f, 7.24f, 0.33f, -1166, 0.020f,    16, 0.030f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_HANGAR          -1000,-1000, 0.0f,10.05f, 0.23f,  -602, 0.020f,   198, 0.030f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY -1000,-4000, 0.0f, 0.30f, 0.10f, -1831, 0.002f, -1630, 0.030f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_HALLWAY         -1000, -300, 0.0f, 1.49f, 0.59f, -1219, 0.007f,   441, 0.011f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR   -1000, -237, 0.0f, 2.70f, 0.79f, -1214, 0.013f,   395, 0.020f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_ALLEY           -1000, -270, 0.0f, 1.49f, 0.86f, -1204, 0.007f,    -4, 0.011f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_FOREST          -1000,-3300, 0.0f, 1.49f, 0.54f, -2560, 0.162f,  -613, 0.088f,  79.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_CITY            -1000, -800, 0.0f, 1.49f, 0.67f, -2273, 0.007f, -2217, 0.011f,  50.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_MOUNTAINS       -1000,-2500, 0.0f, 1.49f, 0.21f, -2780, 0.300f, -2014, 0.100f,  27.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_QUARRY          -1000,-1000, 0.0f, 1.49f, 0.83f,-10000, 0.061f,   500, 0.025f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_PLAIN           -1000,-2000, 0.0f, 1.49f, 0.50f, -2466, 0.179f, -2514, 0.100f,  21.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_PARKINGLOT      -1000,    0, 0.0f, 1.65f, 1.50f, -1363, 0.008f, -1153, 0.012f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_SEWERPIPE       -1000,-1000, 0.0f, 2.81f, 0.14f,   429, 0.014f,   648, 0.021f,  80.0f,  60.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_UNDERWATER      -1000,-4000, 0.0f, 1.49f, 0.10f,  -449, 0.007f,  1700, 0.011f, 100.0f, 100.0f, 5000.0f
+
+//
+// Examples simulating 'musical' reverb presets
+//
+// Name       Decay time   Description
+// Small Room    1.1s      A small size room with a length of 5m or so.
+// Medium Room   1.3s      A medium size room with a length of 10m or so.
+// Large Room    1.5s      A large size room suitable for live performances.
+// Medium Hall   1.8s      A medium size concert hall.
+// Large Hall    1.8s      A large size concert hall suitable for a full orchestra.
+// Plate         1.3s      A plate reverb simulation.
+//
+
+#define I3DL2_ENVIRONMENT_PRESET_SMALLROOM       -1000, -600, 0.0f, 1.10f, 0.83f,  -400, 0.005f,   500, 0.010f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM      -1000, -600, 0.0f, 1.30f, 0.83f, -1000, 0.010f,  -200, 0.020f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_LARGEROOM       -1000, -600, 0.0f, 1.50f, 0.83f, -1600, 0.020f, -1000, 0.040f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL      -1000, -600, 0.0f, 1.80f, 0.70f, -1300, 0.015f,  -800, 0.030f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_LARGEHALL       -1000, -600, 0.0f, 1.80f, 0.70f, -2000, 0.030f, -1400, 0.060f, 100.0f, 100.0f, 5000.0f
+#define I3DL2_ENVIRONMENT_PRESET_PLATE           -1000, -200, 0.0f, 1.30f, 0.90f,     0, 0.002f,     0, 0.010f, 100.0f,  75.0f, 5000.0f
+
+//
+// DirectSound3D Algorithms
+//
+
+// Default DirectSound3D algorithm {00000000-0000-0000-0000-000000000000}
+#define DS3DALG_DEFAULT GUID_NULL
+
+// No virtualization (Pan3D) {C241333F-1C1B-11d2-94F5-00C04FC28ACA}
+DEFINE_GUID(DS3DALG_NO_VIRTUALIZATION, 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca);
+
+// High-quality HRTF algorithm {C2413340-1C1B-11d2-94F5-00C04FC28ACA}
+DEFINE_GUID(DS3DALG_HRTF_FULL, 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca);
+
+// Lower-quality HRTF algorithm {C2413342-1C1B-11d2-94F5-00C04FC28ACA}
+DEFINE_GUID(DS3DALG_HRTF_LIGHT, 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca);
+
+
+#if DIRECTSOUND_VERSION >= 0x0800
+
+//
+// DirectSound Internal Effect Algorithms
+//
+
+
+// Gargle {DAFD8210-5711-4B91-9FE3-F75B7AE279BF}
+DEFINE_GUID(GUID_DSFX_STANDARD_GARGLE, 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf);
+
+// Chorus {EFE6629C-81F7-4281-BD91-C9D604A95AF6}
+DEFINE_GUID(GUID_DSFX_STANDARD_CHORUS, 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6);
+
+// Flanger {EFCA3D92-DFD8-4672-A603-7420894BAD98}
+DEFINE_GUID(GUID_DSFX_STANDARD_FLANGER, 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98);
+
+// Echo/Delay {EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D}
+DEFINE_GUID(GUID_DSFX_STANDARD_ECHO, 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d);
+
+// Distortion {EF114C90-CD1D-484E-96E5-09CFAF912A21}
+DEFINE_GUID(GUID_DSFX_STANDARD_DISTORTION, 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21);
+
+// Compressor/Limiter {EF011F79-4000-406D-87AF-BFFB3FC39D57}
+DEFINE_GUID(GUID_DSFX_STANDARD_COMPRESSOR, 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57);
+
+// Parametric Equalization {120CED89-3BF4-4173-A132-3CB406CF3231}
+DEFINE_GUID(GUID_DSFX_STANDARD_PARAMEQ, 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31);
+
+// I3DL2 Environmental Reverberation: Reverb (Listener) Effect {EF985E71-D5C7-42D4-BA4D-2D073E2E96F4}
+DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4);
+
+// Waves Reverberation {87FC0268-9A55-4360-95AA-004A1D9DE26C}
+DEFINE_GUID(GUID_DSFX_WAVES_REVERB, 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c);
+
+//
+// DirectSound Capture Effect Algorithms
+//
+
+
+// Acoustic Echo Canceller {BF963D80-C559-11D0-8A2B-00A0C9255AC1}
+// Matches KSNODETYPE_ACOUSTIC_ECHO_CANCEL in ksmedia.h
+DEFINE_GUID(GUID_DSCFX_CLASS_AEC, 0xBF963D80L, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1);
+
+// Microsoft AEC {CDEBB919-379A-488a-8765-F53CFD36DE40}
+DEFINE_GUID(GUID_DSCFX_MS_AEC, 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40);
+
+// System AEC {1C22C56D-9879-4f5b-A389-27996DDC2810}
+DEFINE_GUID(GUID_DSCFX_SYSTEM_AEC, 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10);
+
+// Noise Supression {E07F903F-62FD-4e60-8CDD-DEA7236665B5}
+// Matches KSNODETYPE_NOISE_SUPPRESS in post Windows ME DDK's ksmedia.h
+DEFINE_GUID(GUID_DSCFX_CLASS_NS, 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5);
+
+// Microsoft Noise Suppresion {11C5C73B-66E9-4ba1-A0BA-E814C6EED92D}
+DEFINE_GUID(GUID_DSCFX_MS_NS, 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d);
+
+// System Noise Suppresion {5AB0882E-7274-4516-877D-4EEE99BA4FD0}
+DEFINE_GUID(GUID_DSCFX_SYSTEM_NS, 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0);
+
+#endif // DIRECTSOUND_VERSION >= 0x0800
+
+#endif // __DSOUND_INCLUDED__
+
+
+
+#ifdef __cplusplus
+};
+#endif // __cplusplus
+
diff --git a/src/deps/rtaudio-mod/include/ginclude.h b/src/deps/rtaudio-mod/include/ginclude.h
new file mode 100644 (file)
index 0000000..b627dc2
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __gInclude__\r
+#define __gInclude__\r
+\r
+#if SGI \r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef WINDOWS\r
+       //\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_MIPS 1\r
+#elif defined WIN32\r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef SGI\r
+       #define WINDOWS 1\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+#elif BEOS\r
+       #undef MAC \r
+       #undef SGI\r
+       #undef WINDOWS\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+       //\r
+#else\r
+       #define MAC 1\r
+       #undef BEOS \r
+       #undef WINDOWS\r
+       #undef SGI\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_PPC 1\r
+#endif\r
+\r
+// always\r
+#define NATIVE_INT64 0\r
+#define IEEE754_64FLOAT 1\r
+\r
+#endif // __gInclude__\r
diff --git a/src/deps/rtaudio-mod/include/iasiodrv.h b/src/deps/rtaudio-mod/include/iasiodrv.h
new file mode 100644 (file)
index 0000000..64d2dbb
--- /dev/null
@@ -0,0 +1,37 @@
+#include "asiosys.h"\r
+#include "asio.h"\r
+\r
+/* Forward Declarations */ \r
+\r
+#ifndef __ASIODRIVER_FWD_DEFINED__\r
+#define __ASIODRIVER_FWD_DEFINED__\r
+typedef interface IASIO IASIO;\r
+#endif         /* __ASIODRIVER_FWD_DEFINED__ */\r
+\r
+interface IASIO : public IUnknown\r
+{\r
+\r
+       virtual ASIOBool init(void *sysHandle) = 0;\r
+       virtual void getDriverName(char *name) = 0;     \r
+       virtual long getDriverVersion() = 0;\r
+       virtual void getErrorMessage(char *string) = 0; \r
+       virtual ASIOError start() = 0;\r
+       virtual ASIOError stop() = 0;\r
+       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;\r
+       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;\r
+       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
+               long *preferredSize, long *granularity) = 0;\r
+       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;\r
+       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;\r
+       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;\r
+       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;\r
+       virtual ASIOError setClockSource(long reference) = 0;\r
+       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;\r
+       virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;\r
+       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+               long bufferSize, ASIOCallbacks *callbacks) = 0;\r
+       virtual ASIOError disposeBuffers() = 0;\r
+       virtual ASIOError controlPanel() = 0;\r
+       virtual ASIOError future(long selector,void *opt) = 0;\r
+       virtual ASIOError outputReady() = 0;\r
+};\r
diff --git a/src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp b/src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp
new file mode 100644 (file)
index 0000000..08c55ea
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+       IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for
+    the top level description - this comment describes the technical details of
+    the implementation.
+
+    The latest version of this file is available from:
+    http://www.audiomulch.com/~rossb/code/calliasio
+
+    please email comments to Ross Bencina <rossb@audiomulch.com>
+
+    BACKGROUND
+
+    The IASIO interface declared in the Steinberg ASIO 2 SDK declares
+    functions with no explicit calling convention. This causes MSVC++ to default
+    to using the thiscall convention, which is a proprietary convention not
+    implemented by some non-microsoft compilers - notably borland BCC,
+    C++Builder, and gcc. MSVC++ is the defacto standard compiler used by
+    Steinberg. As a result of this situation, the ASIO sdk will compile with
+    any compiler, however attempting to execute the compiled code will cause a
+    crash due to different default calling conventions on non-Microsoft
+    compilers.
+
+    IASIOThiscallResolver solves the problem by providing an adapter class that
+    delegates to the IASIO interface using the correct calling convention
+    (thiscall). Due to the lack of support for thiscall in the Borland and GCC
+    compilers, the calls have been implemented in assembly language.
+
+    A number of macros are defined for thiscall function calls with different
+    numbers of parameters, with and without return values - it may be possible
+    to modify the format of these macros to make them work with other inline
+    assemblers.
+
+
+    THISCALL DEFINITION
+
+    A number of definitions of the thiscall calling convention are floating
+    around the internet. The following definition has been validated against
+    output from the MSVC++ compiler:
+
+    For non-vararg functions, thiscall works as follows: the object (this)
+    pointer is passed in ECX. All arguments are passed on the stack in
+    right to left order. The return value is placed in EAX. The callee
+    clears the passed arguments from the stack.
+
+
+    FINDING FUNCTION POINTERS FROM AN IASIO POINTER
+
+    The first field of a COM object is a pointer to its vtble. Thus a pointer
+    to an object implementing the IASIO interface also points to a pointer to
+    that object's vtbl. The vtble is a table of function pointers for all of
+    the virtual functions exposed by the implemented interfaces.
+
+    If we consider a variable declared as a pointer to IASO:
+
+    IASIO *theAsioDriver
+
+    theAsioDriver points to:
+
+    object implementing IASIO
+    {
+        IASIOvtbl *vtbl
+        other data
+    }
+
+    in other words, theAsioDriver points to a pointer to an IASIOvtbl
+
+    vtbl points to a table of function pointers:
+
+    IASIOvtbl ( interface IASIO : public IUnknown )
+    {
+    (IUnknown functions)
+    0   virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0;
+    4   virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0;
+    8   virtual ULONG STDMETHODCALLTYPE (*Release)() = 0;      
+
+    (IASIO functions)
+    12 virtual ASIOBool (*init)(void *sysHandle) = 0;
+    16 virtual void (*getDriverName)(char *name) = 0;
+    20 virtual long (*getDriverVersion)() = 0;
+    24 virtual void (*getErrorMessage)(char *string) = 0;
+    28 virtual ASIOError (*start)() = 0;
+    32 virtual ASIOError (*stop)() = 0;
+    36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0;
+    40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0;
+    44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize,
+            long *preferredSize, long *granularity) = 0;
+    48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0;
+    52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0;
+    56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0;
+    60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0;
+    64 virtual ASIOError (*setClockSource)(long reference) = 0;
+    68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
+    72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0;
+    76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels,
+            long bufferSize, ASIOCallbacks *callbacks) = 0;
+    80 virtual ASIOError (*disposeBuffers)() = 0;
+    84 virtual ASIOError (*controlPanel)() = 0;
+    88 virtual ASIOError (*future)(long selector,void *opt) = 0;
+    92 virtual ASIOError (*outputReady)() = 0;
+    };
+
+    The numbers in the left column show the byte offset of each function ptr
+    from the beginning of the vtbl. These numbers are used in the code below
+    to select different functions.
+
+    In order to find the address of a particular function, theAsioDriver
+    must first be dereferenced to find the value of the vtbl pointer:
+
+    mov     eax, theAsioDriver
+    mov     edx, [theAsioDriver]  // edx now points to vtbl[0]
+
+    Then an offset must be added to the vtbl pointer to select a
+    particular function, for example vtbl+44 points to the slot containing
+    a pointer to the getBufferSize function.
+
+    Finally vtbl+x must be dereferenced to obtain the value of the function
+    pointer stored in that address:
+
+    call    [edx+44]    // call the function pointed to by
+                        // the value in the getBufferSize field of the vtbl
+
+
+    SEE ALSO
+
+    Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same
+    problem by providing a new COM interface which wraps IASIO with an
+    interface that uses portable calling conventions. OpenASIO must be compiled
+    with MSVC, and requires that you ship the OpenASIO DLL with your
+    application.
+
+    
+    ACKNOWLEDGEMENTS
+
+    Ross Bencina: worked out the thiscall details above, wrote the original
+    Borland asm macros, and a patch for asio.cpp (which is no longer needed).
+    Thanks to Martin Fay for introducing me to the issues discussed here,
+    and to Rene G. Ceballos for assisting with asm dumps from MSVC++.
+
+    Antti Silvast: converted the original calliasio to work with gcc and NASM
+    by implementing the asm code in a separate file.
+
+       Fraser Adams: modified the original calliasio containing the Borland inline
+    asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax
+    for gcc. This seems a neater approach for gcc than to have a separate .asm
+    file and it means that we only need one version of the thiscall patch.
+
+    Fraser Adams: rewrote the original calliasio patch in the form of the
+    IASIOThiscallResolver class in order to avoid modifications to files from
+    the Steinberg SDK, which may have had potential licence issues.
+
+    Andrew Baldwin: contributed fixes for compatibility problems with more
+    recent versions of the gcc assembler.
+*/
+
+
+// We only need IASIOThiscallResolver at all if we are on Win32. For other
+// platforms we simply bypass the IASIOThiscallResolver definition to allow us
+// to be safely #include'd whatever the platform to keep client code portable
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)
+
+
+// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
+// is not used.
+#if !defined(_MSC_VER)
+
+
+#include <new>
+#include <assert.h>
+
+// We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is
+// #include'd before it in client code, we do NOT want to do this test here.
+#define iasiothiscallresolver_sourcefile 1
+#include "iasiothiscallresolver.h"
+#undef iasiothiscallresolver_sourcefile
+
+// iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want
+// this macro defined in this translation unit.
+#undef ASIOInit
+
+
+// theAsioDriver is a global pointer to the current IASIO instance which the
+// ASIO SDK uses to perform all actions on the IASIO interface. We substitute
+// our own forwarding interface into this pointer.
+extern IASIO* theAsioDriver;
+
+
+// The following macros define the inline assembler for BORLAND first then gcc
+
+#if defined(__BCPLUSPLUS__) || defined(__BORLANDC__)          
+
+
+#define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\
+    void *this_ = (thisPtr);                                                \
+    __asm {                                                                 \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+        mov     resultName, eax       ;                                     \
+    }
+
+
+#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\
+    void *this_ = (thisPtr);                                                \
+    __asm {                                                                 \
+        mov     eax, param1           ;                                     \
+        push    eax                   ;                                     \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+    }
+
+
+#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\
+    void *this_ = (thisPtr);                                                \
+    __asm {                                                                 \
+        mov     eax, param1           ;                                     \
+        push    eax                   ;                                     \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+        mov     resultName, eax       ;                                     \
+    }
+
+
+#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\
+    void *this_ = (thisPtr);                                                \
+    void *doubleParamPtr_ (&param1);                                        \
+    __asm {                                                                 \
+        mov     eax, doubleParamPtr_  ;                                     \
+        push    [eax+4]               ;                                     \
+        push    [eax]                 ;                                     \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+        mov     resultName, eax       ;                                     \
+    }
+
+
+#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\
+    void *this_ = (thisPtr);                                                \
+    __asm {                                                                 \
+        mov     eax, param2           ;                                     \
+        push    eax                   ;                                     \
+        mov     eax, param1           ;                                     \
+        push    eax                   ;                                     \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+        mov     resultName, eax       ;                                     \
+    }
+
+
+#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
+    void *this_ = (thisPtr);                                                \
+    __asm {                                                                 \
+        mov     eax, param4           ;                                     \
+        push    eax                   ;                                     \
+        mov     eax, param3           ;                                     \
+        push    eax                   ;                                     \
+        mov     eax, param2           ;                                     \
+        push    eax                   ;                                     \
+        mov     eax, param1           ;                                     \
+        push    eax                   ;                                     \
+        mov     ecx, this_            ;                                     \
+        mov     eax, [ecx]            ;                                     \
+        call    [eax+funcOffset]      ;                                     \
+        mov     resultName, eax       ;                                     \
+    }
+
+
+#elif defined(__GNUC__)
+
+
+#define CALL_THISCALL_0( resultName, thisPtr, funcOffset )                  \
+    __asm__ __volatile__ ("movl (%1), %%edx\n\t"                            \
+                          "call *"#funcOffset"(%%edx)\n\t"                  \
+                          :"=a"(resultName) /* Output Operands */           \
+                          :"c"(thisPtr)     /* Input Operands */            \
+                          : "%edx" /* Clobbered Registers */                \
+                         );                                                 \
+
+
+#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )                 \
+    __asm__ __volatile__ ("pushl %0\n\t"                                    \
+                          "movl (%1), %%edx\n\t"                            \
+                          "call *"#funcOffset"(%%edx)\n\t"                  \
+                          :                 /* Output Operands */           \
+                          :"r"(param1),     /* Input Operands */            \
+                           "c"(thisPtr)                                     \
+                          : "%edx" /* Clobbered Registers */                \
+                         );                                                 \
+
+
+#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )          \
+    __asm__ __volatile__ ("pushl %1\n\t"                                    \
+                          "movl (%2), %%edx\n\t"                            \
+                          "call *"#funcOffset"(%%edx)\n\t"                  \
+                          :"=a"(resultName) /* Output Operands */           \
+                          :"r"(param1),     /* Input Operands */            \
+                           "c"(thisPtr)                                     \
+                          : "%edx" /* Clobbered Registers */                \
+                          );                                                \
+
+
+#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )   \
+    do {                                                                    \
+    double param1f64 = param1; /* Cast explicitly to double */              \
+    double *param1f64Ptr = &param1f64; /* Make pointer to address */        \
+     __asm__ __volatile__ ("pushl 4(%1)\n\t"                                \
+                           "pushl (%1)\n\t"                                 \
+                           "movl (%2), %%edx\n\t"                           \
+                           "call *"#funcOffset"(%%edx);\n\t"                \
+                           : "=a"(resultName) /* Output Operands */         \
+                           : "r"(param1f64Ptr),  /* Input Operands */       \
+                           "c"(thisPtr),                                    \
+                           "m"(*param1f64Ptr) /* Using address */           \
+                           : "%edx" /* Clobbered Registers */               \
+                           );                                               \
+    } while (0);                                                            \
+
+
+#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )  \
+    __asm__ __volatile__ ("pushl %1\n\t"                                    \
+                          "pushl %2\n\t"                                    \
+                          "movl (%3), %%edx\n\t"                            \
+                          "call *"#funcOffset"(%%edx)\n\t"                  \
+                          :"=a"(resultName) /* Output Operands */           \
+                          :"r"(param2),     /* Input Operands */            \
+                           "r"(param1),                                     \
+                           "c"(thisPtr)                                     \
+                          : "%edx" /* Clobbered Registers */                \
+                          );                                                \
+
+
+#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
+    __asm__ __volatile__ ("pushl %1\n\t"                                    \
+                          "pushl %2\n\t"                                    \
+                          "pushl %3\n\t"                                    \
+                          "pushl %4\n\t"                                    \
+                          "movl (%5), %%edx\n\t"                            \
+                          "call *"#funcOffset"(%%edx)\n\t"                  \
+                          :"=a"(resultName) /* Output Operands */           \
+                          :"r"(param4),     /* Input Operands  */           \
+                           "r"(param3),                                     \
+                           "r"(param2),                                     \
+                           "r"(param1),                                     \
+                           "c"(thisPtr)                                     \
+                          : "%edx" /* Clobbered Registers */                \
+                          );                                                \
+
+#endif
+
+
+
+// Our static singleton instance.
+IASIOThiscallResolver IASIOThiscallResolver::instance;
+
+// Constructor called to initialize static Singleton instance above. Note that
+// it is important not to clear that_ incase it has already been set by the call
+// to placement new in ASIOInit().
+IASIOThiscallResolver::IASIOThiscallResolver()
+{
+}
+
+// Constructor called from ASIOInit() below
+IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that)
+: that_( that )
+{
+}
+
+// Implement IUnknown methods as assert(false). IASIOThiscallResolver is not
+// really a COM object, just a wrapper which will work with the ASIO SDK.
+// If you wanted to use ASIO without the SDK you might want to implement COM
+// aggregation in these methods.
+HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv)
+{
+    (void)riid;     // suppress unused variable warning
+
+    assert( false ); // this function should never be called by the ASIO SDK.
+
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef()
+{
+    assert( false ); // this function should never be called by the ASIO SDK.
+
+    return 1;
+}
+
+ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release()
+{
+    assert( false ); // this function should never be called by the ASIO SDK.
+    
+    return 1;
+}
+
+
+// Implement the IASIO interface methods by performing the vptr manipulation
+// described above then delegating to the real implementation.
+ASIOBool IASIOThiscallResolver::init(void *sysHandle)
+{
+    ASIOBool result;
+    CALL_THISCALL_1( result, that_, 12, sysHandle );
+    return result;
+}
+
+void IASIOThiscallResolver::getDriverName(char *name)
+{
+    CALL_VOID_THISCALL_1( that_, 16, name );
+}
+
+long IASIOThiscallResolver::getDriverVersion()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 20 );
+    return result;
+}
+
+void IASIOThiscallResolver::getErrorMessage(char *string)
+{
+     CALL_VOID_THISCALL_1( that_, 24, string );
+}
+
+ASIOError IASIOThiscallResolver::start()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 28 );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::stop()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 32 );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels)
+{
+    ASIOBool result;
+    CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency)
+{
+    ASIOBool result;
+    CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize,
+        long *preferredSize, long *granularity)
+{
+    ASIOBool result;
+    CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate)
+{
+    ASIOBool result;
+    CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate)
+{
+    ASIOBool result;
+    CALL_THISCALL_1( result, that_, 52, sampleRate );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate)
+{    
+    ASIOBool result;
+    CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources)
+{
+    ASIOBool result;
+    CALL_THISCALL_2( result, that_, 60, clocks, numSources );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::setClockSource(long reference)
+{
+    ASIOBool result;
+    CALL_THISCALL_1( result, that_, 64, reference );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
+{
+    ASIOBool result;
+    CALL_THISCALL_2( result, that_, 68, sPos, tStamp );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info)
+{
+    ASIOBool result;
+    CALL_THISCALL_1( result, that_, 72, info );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos,
+        long numChannels, long bufferSize, ASIOCallbacks *callbacks)
+{
+    ASIOBool result;
+    CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::disposeBuffers()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 80 );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::controlPanel()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 84 );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::future(long selector,void *opt)
+{
+    ASIOBool result;
+    CALL_THISCALL_2( result, that_, 88, selector, opt );
+    return result;
+}
+
+ASIOError IASIOThiscallResolver::outputReady()
+{
+    ASIOBool result;
+    CALL_THISCALL_0( result, that_, 92 );
+    return result;
+}
+
+
+// Implement our substitute ASIOInit() method
+ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info)
+{
+    // To ensure that our instance's vptr is correctly constructed, even if
+    // ASIOInit is called prior to main(), we explicitly call its constructor
+    // (potentially over the top of an existing instance). Note that this is
+    // pretty ugly, and is only safe because IASIOThiscallResolver has no
+    // destructor and contains no objects with destructors.
+    new((void*)&instance) IASIOThiscallResolver( theAsioDriver );
+
+    // Interpose between ASIO client code and the real driver.
+    theAsioDriver = &instance;
+
+    // Note that we never need to switch theAsioDriver back to point to the
+    // real driver because theAsioDriver is reset to zero in ASIOExit().
+
+    // Delegate to the real ASIOInit
+       return ::ASIOInit(info);
+}
+
+
+#endif /* !defined(_MSC_VER) */
+
+#endif /* Win32 */
+
diff --git a/src/deps/rtaudio-mod/include/iasiothiscallresolver.h b/src/deps/rtaudio-mod/include/iasiothiscallresolver.h
new file mode 100644 (file)
index 0000000..63e91ca
--- /dev/null
@@ -0,0 +1,202 @@
+// ****************************************************************************\r
+//\r
+// Changed:         I have modified this file slightly (includes) to work  with\r
+//                  RtAudio. RtAudio.cpp must include this file after asio.h.                                                    \r
+//\r
+// File:                       IASIOThiscallResolver.h\r
+// Description:     The IASIOThiscallResolver class implements the IASIO\r
+//                                     interface and acts as a proxy to the real IASIO interface by\r
+//                  calling through its vptr table using the thiscall calling\r
+//                  convention. To put it another way, we interpose\r
+//                  IASIOThiscallResolver between ASIO SDK code and the driver.\r
+//                  This is necessary because most non-Microsoft compilers don't\r
+//                  implement the thiscall calling convention used by IASIO.\r
+//\r
+//                                     iasiothiscallresolver.cpp contains the background of this\r
+//                                     problem plus a technical description of the vptr\r
+//                  manipulations.\r
+//\r
+//                                     In order to use this mechanism one simply has to add\r
+//                                     iasiothiscallresolver.cpp to the list of files to compile\r
+//                  and #include <iasiothiscallresolver.h>\r
+//\r
+//                                     Note that this #include must come after the other ASIO SDK\r
+//                  #includes, for example:\r
+//\r
+//                                     #include <windows.h>\r
+//                                     #include <asiosys.h>\r
+//                                     #include <asio.h>\r
+//                                     #include <asiodrivers.h>\r
+//                                     #include <iasiothiscallresolver.h>\r
+//\r
+//                                     Actually the important thing is to #include\r
+//                  <iasiothiscallresolver.h> after <asio.h>. We have\r
+//                  incorporated a test to enforce this ordering.\r
+//\r
+//                                     The code transparently takes care of the interposition by\r
+//                  using macro substitution to intercept calls to ASIOInit()\r
+//                  and ASIOExit(). We save the original ASIO global\r
+//                  "theAsioDriver" in our "that" variable, and then set\r
+//                  "theAsioDriver" to equal our IASIOThiscallResolver instance.\r
+//\r
+//                                     Whilst this method of resolving the thiscall problem requires\r
+//                                     the addition of #include <iasiothiscallresolver.h> to client\r
+//                  code it has the advantage that it does not break the terms\r
+//                  of the ASIO licence by publishing it. We are NOT modifying\r
+//                  any Steinberg code here, we are merely implementing the IASIO\r
+//                                     interface in the same way that we would need to do if we\r
+//                                     wished to provide an open source ASIO driver.\r
+//\r
+//                                     For compilation with MinGW -lole32 needs to be added to the\r
+//                  linker options. For BORLAND, linking with Import32.lib is\r
+//                  sufficient.\r
+//\r
+//                                     The dependencies are with: CoInitialize, CoUninitialize,\r
+//                                     CoCreateInstance, CLSIDFromString - used by asiolist.cpp\r
+//                                     and are required on Windows whether ThiscallResolver is used\r
+//                                     or not.\r
+//\r
+//                                     Searching for the above strings in the root library path\r
+//                                     of your compiler should enable the correct libraries to be\r
+//                                     identified if they aren't immediately obvious.\r
+//\r
+//                  Note that the current implementation of IASIOThiscallResolver\r
+//                  is not COM compliant - it does not correctly implement the\r
+//                  IUnknown interface. Implementing it is not necessary because\r
+//                  it is not called by parts of the ASIO SDK which call through\r
+//                  theAsioDriver ptr. The IUnknown methods are implemented as\r
+//                  assert(false) to ensure that the code fails if they are\r
+//                  ever called.\r
+// Restrictions:       None. Public Domain & Open Source distribute freely\r
+//                                     You may use IASIOThiscallResolver commercially as well as\r
+//                  privately.\r
+//                                     You the user assume the responsibility for the use of the\r
+//                                     files, binary or text, and there is no guarantee or warranty,\r
+//                                     expressed or implied, including but not limited to the\r
+//                                     implied warranties of merchantability and fitness for a\r
+//                                     particular purpose. You assume all responsibility and agree\r
+//                                     to hold no entity, copyright holder or distributors liable\r
+//                                     for any loss of data or inaccurate representations of data\r
+//                                     as a result of using IASIOThiscallResolver.\r
+// Version:         1.4 Added separate macro CALL_THISCALL_1_DOUBLE from\r
+//                  Andrew Baldwin, and volatile for whole gcc asm blocks,\r
+//                  both for compatibility with newer gcc versions. Cleaned up\r
+//                  Borland asm to use one less register.\r
+//                  1.3 Switched to including assert.h for better compatibility.\r
+//                  Wrapped entire .h and .cpp contents with a check for\r
+//                  _MSC_VER to provide better compatibility with MS compilers.\r
+//                  Changed Singleton implementation to use static instance\r
+//                  instead of freestore allocated instance. Removed ASIOExit\r
+//                  macro as it is no longer needed.\r
+//                  1.2 Removed semicolons from ASIOInit and ASIOExit macros to\r
+//                  allow them to be embedded in expressions (if statements).\r
+//                  Cleaned up some comments. Removed combase.c dependency (it\r
+//                  doesn't compile with BCB anyway) by stubbing IUnknown.\r
+//                  1.1 Incorporated comments from Ross Bencina including things\r
+//                                     such as changing name from ThiscallResolver to\r
+//                                     IASIOThiscallResolver, tidying up the constructor, fixing\r
+//                                     a bug in IASIOThiscallResolver::ASIOExit() and improving\r
+//                                     portability through the use of conditional compilation\r
+//                                     1.0 Initial working version.\r
+// Created:                    6/09/2003\r
+// Authors:         Fraser Adams\r
+//                  Ross Bencina\r
+//                  Rene G. Ceballos\r
+//                  Martin Fay\r
+//                  Antti Silvast\r
+//                  Andrew Baldwin\r
+//\r
+// ****************************************************************************\r
+\r
+\r
+#ifndef included_iasiothiscallresolver_h\r
+#define included_iasiothiscallresolver_h\r
+\r
+// We only need IASIOThiscallResolver at all if we are on Win32. For other\r
+// platforms we simply bypass the IASIOThiscallResolver definition to allow us\r
+// to be safely #include'd whatever the platform to keep client code portable\r
+//#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)\r
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64)\r
+\r
+\r
+// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver\r
+// is not used.\r
+#if !defined(_MSC_VER)\r
+\r
+\r
+// The following is in order to ensure that this header is only included after\r
+// the other ASIO headers (except for the case of iasiothiscallresolver.cpp).\r
+// We need to do this because IASIOThiscallResolver works by eclipsing the\r
+// original definition of ASIOInit() with a macro (see below).\r
+#if !defined(iasiothiscallresolver_sourcefile)\r
+       #if !defined(__ASIO_H)\r
+       #error iasiothiscallresolver.h must be included AFTER asio.h\r
+       #endif\r
+#endif\r
+\r
+#include <windows.h>\r
+#include "iasiodrv.h" /* From ASIO SDK */\r
+\r
+\r
+class IASIOThiscallResolver : public IASIO {\r
+private:\r
+       IASIO* that_; // Points to the real IASIO\r
+\r
+       static IASIOThiscallResolver instance; // Singleton instance\r
+\r
+       // Constructors - declared private so construction is limited to\r
+    // our Singleton instance\r
+    IASIOThiscallResolver();\r
+       IASIOThiscallResolver(IASIO* that);\r
+public:\r
+\r
+    // Methods from the IUnknown interface. We don't fully implement IUnknown\r
+    // because the ASIO SDK never calls these methods through theAsioDriver ptr.\r
+    // These methods are implemented as assert(false).\r
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);\r
+    virtual ULONG STDMETHODCALLTYPE AddRef();\r
+    virtual ULONG STDMETHODCALLTYPE Release();\r
+\r
+    // Methods from the IASIO interface, implemented as forwarning calls to that.\r
+       virtual ASIOBool init(void *sysHandle);\r
+       virtual void getDriverName(char *name);\r
+       virtual long getDriverVersion();\r
+       virtual void getErrorMessage(char *string);\r
+       virtual ASIOError start();\r
+       virtual ASIOError stop();\r
+       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);\r
+       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);\r
+       virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);\r
+       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);\r
+       virtual ASIOError setClockSource(long reference);\r
+       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+       virtual ASIOError getChannelInfo(ASIOChannelInfo *info);\r
+       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);\r
+       virtual ASIOError disposeBuffers();\r
+       virtual ASIOError controlPanel();\r
+       virtual ASIOError future(long selector,void *opt);\r
+       virtual ASIOError outputReady();\r
+\r
+    // Class method, see ASIOInit() macro below.\r
+    static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit\r
+};\r
+\r
+\r
+// Replace calls to ASIOInit with our interposing version.\r
+// This macro enables us to perform thiscall resolution simply by #including\r
+// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be\r
+// included _after_ the asio #includes)\r
+\r
+#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))\r
+\r
+\r
+#endif /* !defined(_MSC_VER) */\r
+\r
+#endif /* Win32 */\r
+\r
+#endif /* included_iasiothiscallresolver_h */\r
+\r
+\r
diff --git a/src/deps/rtaudio-mod/include/soundcard.h b/src/deps/rtaudio-mod/include/soundcard.h
new file mode 100644 (file)
index 0000000..2cf3a2c
--- /dev/null
@@ -0,0 +1,1878 @@
+/*
+ * soundcard.h
+ */
+
+/*-
+ * Copyright by Hannu Savolainen 1993 / 4Front Technologies 1993-2006
+ * Modified for the new FreeBSD sound driver by Luigi Rizzo, 1997
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/soundcard.h,v 1.48 2006/11/26 11:55:48 netchild Exp $
+ */
+
+/*
+ * Unless coordinating changes with 4Front Technologies, do NOT make any
+ * modifications to ioctl commands, types, etc. that would break
+ * compatibility with the OSS API.
+ */
+
+#ifndef _SYS_SOUNDCARD_H_
+#define _SYS_SOUNDCARD_H_
+ /*
+  * If you make modifications to this file, please contact me before
+  * distributing the modified version. There is already enough
+  * diversity in the world.
+  *
+  * Regards,
+  * Hannu Savolainen
+  * hannu@voxware.pp.fi
+  *
+  **********************************************************************
+  * PS.        The Hacker's Guide to VoxWare available from
+  *     nic.funet.fi:pub/Linux/ALPHA/sound. The file is
+  *    snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains
+  *    some useful information about programming with VoxWare.
+  *    (NOTE! The pub/Linux/ALPHA/ directories are hidden. You have
+  *    to cd inside them before the files are accessible.)
+  **********************************************************************
+  */
+
+/*
+ * SOUND_VERSION is only used by the voxware driver. Hopefully apps
+ * should not depend on it, but rather look at the capabilities
+ * of the driver in the kernel!
+ */
+#define SOUND_VERSION  301
+#define VOXWARE                /* does this have any use ? */
+
+/*
+ * Supported card ID numbers (Should be somewhere else? We keep
+ * them here just for compativility with the old driver, but these
+ * constants are of little or no use).
+ */
+
+#define SNDCARD_ADLIB          1
+#define SNDCARD_SB             2
+#define SNDCARD_PAS            3
+#define SNDCARD_GUS            4
+#define SNDCARD_MPU401         5
+#define SNDCARD_SB16           6
+#define SNDCARD_SB16MIDI       7
+#define SNDCARD_UART6850       8
+#define SNDCARD_GUS16          9
+#define SNDCARD_MSS            10
+#define SNDCARD_PSS            11
+#define SNDCARD_SSCAPE         12
+#define SNDCARD_PSS_MPU        13
+#define SNDCARD_PSS_MSS        14
+#define SNDCARD_SSCAPE_MSS     15
+#define SNDCARD_TRXPRO         16
+#define SNDCARD_TRXPRO_SB      17
+#define SNDCARD_TRXPRO_MPU     18
+#define SNDCARD_MAD16          19
+#define SNDCARD_MAD16_MPU      20
+#define SNDCARD_CS4232         21
+#define SNDCARD_CS4232_MPU     22
+#define SNDCARD_MAUI           23
+#define SNDCARD_PSEUDO_MSS     24
+#define SNDCARD_AWE32          25
+#define SNDCARD_NSS            26
+#define SNDCARD_UART16550      27
+#define SNDCARD_OPL            28
+
+#include <sys/types.h>
+#include <machine/endian.h>
+#ifndef _IOWR
+#include <sys/ioccom.h>
+#endif  /* !_IOWR */
+
+/*
+ * The first part of this file contains the new FreeBSD sound ioctl
+ * interface. Tries to minimize the number of different ioctls, and
+ * to be reasonably general.
+ *
+ * 970821: some of the new calls have not been implemented yet.
+ */
+
+/*
+ * the following three calls extend the generic file descriptor
+ * interface. AIONWRITE is the dual of FIONREAD, i.e. returns the max
+ * number of bytes for a write operation to be non-blocking.
+ *
+ * AIOGSIZE/AIOSSIZE are used to change the behaviour of the device,
+ * from a character device (default) to a block device. In block mode,
+ * (not to be confused with blocking mode) the main difference for the
+ * application is that select() will return only when a complete
+ * block can be read/written to the device, whereas in character mode
+ * select will return true when one byte can be exchanged. For audio
+ * devices, character mode makes select almost useless since one byte
+ * will always be ready by the next sample time (which is often only a
+ * handful of microseconds away).
+ * Use a size of 0 or 1 to return to character mode.
+ */
+#define        AIONWRITE   _IOR('A', 10, int)   /* get # bytes to write */
+struct snd_size {
+    int play_size;
+    int rec_size;
+};
+#define        AIOGSIZE    _IOR('A', 11, struct snd_size)/* read current blocksize */
+#define        AIOSSIZE    _IOWR('A', 11, struct snd_size)  /* sets blocksize */
+
+/*
+ * The following constants define supported audio formats. The
+ * encoding follows voxware conventions, i.e. 1 bit for each supported
+ * format. We extend it by using bit 31 (RO) to indicate full-duplex
+ * capability, and bit 29 (RO) to indicate that the card supports/
+ * needs different formats on capture & playback channels.
+ * Bit 29 (RW) is used to indicate/ask stereo.
+ *
+ * The number of bits required to store the sample is:
+ *  o  4 bits for the IDA ADPCM format,
+ *  o  8 bits for 8-bit formats, mu-law and A-law,
+ *  o  16 bits for the 16-bit formats, and
+ *  o  32 bits for the 24/32-bit formats.
+ *  o  undefined for the MPEG audio format.
+ */
+
+#define AFMT_QUERY     0x00000000      /* Return current format */
+#define AFMT_MU_LAW    0x00000001      /* Logarithmic mu-law */
+#define AFMT_A_LAW     0x00000002      /* Logarithmic A-law */
+#define AFMT_IMA_ADPCM 0x00000004      /* A 4:1 compressed format where 16-bit
+                                        * squence represented using the
+                                        * the average 4 bits per sample */
+#define AFMT_U8                0x00000008      /* Unsigned 8-bit */
+#define AFMT_S16_LE    0x00000010      /* Little endian signed 16-bit */
+#define AFMT_S16_BE    0x00000020      /* Big endian signed 16-bit */
+#define AFMT_S8                0x00000040      /* Signed 8-bit */
+#define AFMT_U16_LE    0x00000080      /* Little endian unsigned 16-bit */
+#define AFMT_U16_BE    0x00000100      /* Big endian unsigned 16-bit */
+#define AFMT_MPEG      0x00000200      /* MPEG MP2/MP3 audio */
+#define AFMT_AC3       0x00000400      /* Dolby Digital AC3 */
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define AFMT_S16_NE    AFMT_S16_LE     /* native endian signed 16 */
+#else
+#define AFMT_S16_NE    AFMT_S16_BE
+#endif
+
+/*
+ * 32-bit formats below used for 24-bit audio data where the data is stored
+ * in the 24 most significant bits and the least significant bits are not used
+ * (should be set to 0).
+ */
+#define AFMT_S32_LE    0x00001000      /* Little endian signed 32-bit */
+#define AFMT_S32_BE    0x00002000      /* Big endian signed 32-bit */
+#define AFMT_U32_LE    0x00004000      /* Little endian unsigned 32-bit */
+#define AFMT_U32_BE    0x00008000      /* Big endian unsigned 32-bit */
+#define AFMT_S24_LE    0x00010000      /* Little endian signed 24-bit */
+#define AFMT_S24_BE    0x00020000      /* Big endian signed 24-bit */
+#define AFMT_U24_LE    0x00040000      /* Little endian unsigned 24-bit */
+#define AFMT_U24_BE    0x00080000      /* Big endian unsigned 24-bit */
+
+#define AFMT_STEREO    0x10000000      /* can do/want stereo   */
+
+/*
+ * the following are really capabilities
+ */
+#define AFMT_WEIRD     0x20000000      /* weird hardware...    */
+    /*
+     * AFMT_WEIRD reports that the hardware might need to operate
+     * with different formats in the playback and capture
+     * channels when operating in full duplex.
+     * As an example, SoundBlaster16 cards only support U8 in one
+     * direction and S16 in the other one, and applications should
+     * be aware of this limitation.
+     */
+#define AFMT_FULLDUPLEX        0x80000000      /* can do full duplex   */
+
+/*
+ * The following structure is used to get/set format and sampling rate.
+ * While it would be better to have things such as stereo, bits per
+ * sample, endiannes, etc split in different variables, it turns out
+ * that formats are not that many, and not all combinations are possible.
+ * So we followed the Voxware approach of associating one bit to each
+ * format.
+ */
+
+typedef struct _snd_chan_param {
+    u_long     play_rate;      /* sampling rate                        */
+    u_long     rec_rate;       /* sampling rate                        */
+    u_long     play_format;    /* everything describing the format     */
+    u_long     rec_format;     /* everything describing the format     */
+} snd_chan_param;
+#define        AIOGFMT    _IOR('f', 12, snd_chan_param)   /* get format */
+#define        AIOSFMT    _IOWR('f', 12, snd_chan_param)  /* sets format */
+
+/*
+ * The following structure is used to get/set the mixer setting.
+ * Up to 32 mixers are supported, each one with up to 32 channels.
+ */
+typedef struct _snd_mix_param {
+    u_char     subdev; /* which output                         */
+    u_char     line;   /* which input                          */
+    u_char     left,right; /* volumes, 0..255, 0 = mute        */
+} snd_mix_param ;
+
+/* XXX AIOGMIX, AIOSMIX not implemented yet */
+#define AIOGMIX        _IOWR('A', 13, snd_mix_param)   /* return mixer status */
+#define AIOSMIX        _IOWR('A', 14, snd_mix_param)   /* sets mixer status   */
+
+/*
+ * channel specifiers used in AIOSTOP and AIOSYNC
+ */
+#define        AIOSYNC_PLAY    0x1     /* play chan */
+#define        AIOSYNC_CAPTURE 0x2     /* capture chan */
+/* AIOSTOP stop & flush a channel, returns the residual count */
+#define        AIOSTOP _IOWR ('A', 15, int)
+
+/* alternate method used to notify the sync condition */
+#define        AIOSYNC_SIGNAL  0x100
+#define        AIOSYNC_SELECT  0x200
+
+/* what the 'pos' field refers to */
+#define AIOSYNC_READY  0x400
+#define AIOSYNC_FREE   0x800
+
+typedef struct _snd_sync_parm {
+    long chan ; /* play or capture channel, plus modifier */
+    long pos;
+} snd_sync_parm;
+#define        AIOSYNC _IOWR ('A', 15, snd_sync_parm)  /* misc. synchronization */
+
+/*
+ * The following is used to return device capabilities. If the structure
+ * passed to the ioctl is zeroed, default values are returned for rate
+ * and formats, a bitmap of available mixers is returned, and values
+ * (inputs, different levels) for the first one are returned.
+ *
+ * If  formats, mixers, inputs are instantiated, then detailed info
+ * are returned depending on the call.
+ */
+typedef struct _snd_capabilities {
+    u_long     rate_min, rate_max;     /* min-max sampling rate */
+    u_long     formats;
+    u_long     bufsize; /* DMA buffer size */
+    u_long     mixers; /* bitmap of available mixers */
+    u_long     inputs; /* bitmap of available inputs (per mixer) */
+    u_short    left, right;    /* how many levels are supported */
+} snd_capabilities;
+#define AIOGCAP        _IOWR('A', 15, snd_capabilities)        /* get capabilities */
+
+/*
+ * here is the old (Voxware) ioctl interface
+ */
+
+/*
+ * IOCTL Commands for /dev/sequencer
+ */
+
+#define SNDCTL_SEQ_RESET       _IO  ('Q', 0)
+#define SNDCTL_SEQ_SYNC                _IO  ('Q', 1)
+#define SNDCTL_SYNTH_INFO      _IOWR('Q', 2, struct synth_info)
+#define SNDCTL_SEQ_CTRLRATE    _IOWR('Q', 3, int) /* Set/get timer res.(hz) */
+#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
+#define SNDCTL_SEQ_GETINCOUNT  _IOR ('Q', 5, int)
+#define SNDCTL_SEQ_PERCMODE    _IOW ('Q', 6, int)
+#define SNDCTL_FM_LOAD_INSTR   _IOW ('Q', 7, struct sbi_instrument)    /* Valid for FM only */
+#define SNDCTL_SEQ_TESTMIDI    _IOW ('Q', 8, int)
+#define SNDCTL_SEQ_RESETSAMPLES        _IOW ('Q', 9, int)
+#define SNDCTL_SEQ_NRSYNTHS    _IOR ('Q',10, int)
+#define SNDCTL_SEQ_NRMIDIS     _IOR ('Q',11, int)
+#define SNDCTL_MIDI_INFO       _IOWR('Q',12, struct midi_info)
+#define SNDCTL_SEQ_THRESHOLD   _IOW ('Q',13, int)
+#define SNDCTL_SEQ_TRESHOLD    SNDCTL_SEQ_THRESHOLD    /* there was once a typo */
+#define SNDCTL_SYNTH_MEMAVL    _IOWR('Q',14, int) /* in=dev#, out=memsize */
+#define SNDCTL_FM_4OP_ENABLE   _IOW ('Q',15, int) /* in=dev# */
+#define SNDCTL_PMGR_ACCESS     _IOWR('Q',16, struct patmgr_info)
+#define SNDCTL_SEQ_PANIC       _IO  ('Q',17)
+#define SNDCTL_SEQ_OUTOFBAND   _IOW ('Q',18, struct seq_event_rec)
+#define SNDCTL_SEQ_GETTIME     _IOR ('Q',19, int)
+
+struct seq_event_rec {
+       u_char arr[8];
+};
+
+#define SNDCTL_TMR_TIMEBASE    _IOWR('T', 1, int)
+#define SNDCTL_TMR_START       _IO  ('T', 2)
+#define SNDCTL_TMR_STOP                _IO  ('T', 3)
+#define SNDCTL_TMR_CONTINUE    _IO  ('T', 4)
+#define SNDCTL_TMR_TEMPO       _IOWR('T', 5, int)
+#define SNDCTL_TMR_SOURCE      _IOWR('T', 6, int)
+#   define TMR_INTERNAL                0x00000001
+#   define TMR_EXTERNAL                0x00000002
+#      define TMR_MODE_MIDI    0x00000010
+#      define TMR_MODE_FSK     0x00000020
+#      define TMR_MODE_CLS     0x00000040
+#      define TMR_MODE_SMPTE   0x00000080
+#define SNDCTL_TMR_METRONOME   _IOW ('T', 7, int)
+#define SNDCTL_TMR_SELECT      _IOW ('T', 8, int)
+
+/*
+ *     Endian aware patch key generation algorithm.
+ */
+
+#if defined(_AIX) || defined(AIX)
+#  define _PATCHKEY(id) (0xfd00|id)
+#else
+#  define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*
+ *     Sample loading mechanism for internal synthesizers (/dev/sequencer)
+ *     The following patch_info structure has been designed to support
+ *     Gravis UltraSound. It tries to be universal format for uploading
+ *     sample based patches but is probably too limited.
+ */
+
+struct patch_info {
+/*             u_short key;             Use GUS_PATCH here */
+       short key;               /* Use GUS_PATCH here */
+#define GUS_PATCH      _PATCHKEY(0x04)
+#define OBSOLETE_GUS_PATCH     _PATCHKEY(0x02)
+
+       short device_no;        /* Synthesizer number */
+       short instr_no;         /* Midi pgm# */
+
+       u_long mode;
+/*
+ * The least significant byte has the same format than the GUS .PAT
+ * files
+ */
+#define WAVE_16_BITS   0x01    /* bit 0 = 8 or 16 bit wave data. */
+#define WAVE_UNSIGNED  0x02    /* bit 1 = Signed - Unsigned data. */
+#define WAVE_LOOPING   0x04    /* bit 2 = looping enabled-1. */
+#define WAVE_BIDIR_LOOP        0x08    /* bit 3 = Set is bidirectional looping. */
+#define WAVE_LOOP_BACK 0x10    /* bit 4 = Set is looping backward. */
+#define WAVE_SUSTAIN_ON        0x20    /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
+#define WAVE_ENVELOPES 0x40    /* bit 6 = Enable envelopes - 1 */
+                               /*      (use the env_rate/env_offs fields). */
+/* Linux specific bits */
+#define WAVE_VIBRATO   0x00010000      /* The vibrato info is valid */
+#define WAVE_TREMOLO   0x00020000      /* The tremolo info is valid */
+#define WAVE_SCALE     0x00040000      /* The scaling info is valid */
+/* Other bits must be zeroed */
+
+       long len;       /* Size of the wave data in bytes */
+       long loop_start, loop_end; /* Byte offsets from the beginning */
+
+/*
+ * The base_freq and base_note fields are used when computing the
+ * playback speed for a note. The base_note defines the tone frequency
+ * which is heard if the sample is played using the base_freq as the
+ * playback speed.
+ *
+ * The low_note and high_note fields define the minimum and maximum note
+ * frequencies for which this sample is valid. It is possible to define
+ * more than one samples for an instrument number at the same time. The
+ * low_note and high_note fields are used to select the most suitable one.
+ *
+ * The fields base_note, high_note and low_note should contain
+ * the note frequency multiplied by 1000. For example value for the
+ * middle A is 440*1000.
+ */
+
+       u_int base_freq;
+       u_long base_note;
+       u_long high_note;
+       u_long low_note;
+       int panning;    /* -128=left, 127=right */
+       int detuning;
+
+/*     New fields introduced in version 1.99.5 */
+
+       /* Envelope. Enabled by mode bit WAVE_ENVELOPES */
+       u_char  env_rate[ 6 ];   /* GUS HW ramping rate */
+       u_char  env_offset[ 6 ]; /* 255 == 100% */
+
+       /*
+        * The tremolo, vibrato and scale info are not supported yet.
+        * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
+        * WAVE_SCALE
+        */
+
+       u_char  tremolo_sweep;
+       u_char  tremolo_rate;
+       u_char  tremolo_depth;
+
+       u_char  vibrato_sweep;
+       u_char  vibrato_rate;
+       u_char  vibrato_depth;
+
+       int             scale_frequency;
+       u_int   scale_factor;           /* from 0 to 2048 or 0 to 2 */
+
+       int             volume;
+       int             spare[4];
+       char data[1];   /* The waveform data starts here */
+};
+
+struct sysex_info {
+       short key;              /* Use GUS_PATCH here */
+#define SYSEX_PATCH    _PATCHKEY(0x05)
+#define MAUI_PATCH     _PATCHKEY(0x06)
+       short device_no;        /* Synthesizer number */
+       long len;       /* Size of the sysex data in bytes */
+       u_char data[1]; /* Sysex data starts here */
+};
+
+/*
+ * Patch management interface (/dev/sequencer, /dev/patmgr#)
+ * Don't use these calls if you want to maintain compatibility with
+ * the future versions of the driver.
+ */
+
+#define PS_NO_PATCHES          0       /* No patch support on device */
+#define        PS_MGR_NOT_OK           1       /* Plain patch support (no mgr) */
+#define        PS_MGR_OK               2       /* Patch manager supported */
+#define        PS_MANAGED              3       /* Patch manager running */
+
+#define SNDCTL_PMGR_IFACE              _IOWR('P', 1, struct patmgr_info)
+
+/*
+ * The patmgr_info is a fixed size structure which is used for two
+ * different purposes. The intended use is for communication between
+ * the application using /dev/sequencer and the patch manager daemon
+ * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)).
+ *
+ * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows
+ * a patch manager daemon to read and write device parameters. This
+ * ioctl available through /dev/sequencer also. Avoid using it since it's
+ * extremely hardware dependent. In addition access trough /dev/sequencer
+ * may confuse the patch manager daemon.
+ */
+
+struct patmgr_info {   /* Note! size must be < 4k since kmalloc() is used */
+         u_long key;   /* Don't worry. Reserved for communication
+                                  between the patch manager and the driver. */
+#define PM_K_EVENT             1 /* Event from the /dev/sequencer driver */
+#define PM_K_COMMAND           2 /* Request from an application */
+#define PM_K_RESPONSE          3 /* From patmgr to application */
+#define PM_ERROR               4 /* Error returned by the patmgr */
+         int device;
+         int command;
+
+/*
+ * Commands 0x000 to 0xfff reserved for patch manager programs
+ */
+#define PM_GET_DEVTYPE 1       /* Returns type of the patch mgr interface of dev */
+#define                PMTYPE_FM2      1       /* 2 OP fm */
+#define                PMTYPE_FM4      2       /* Mixed 4 or 2 op FM (OPL-3) */
+#define                PMTYPE_WAVE     3       /* Wave table synthesizer (GUS) */
+#define PM_GET_NRPGM   2       /* Returns max # of midi programs in parm1 */
+#define PM_GET_PGMMAP  3       /* Returns map of loaded midi programs in data8 */
+#define PM_GET_PGM_PATCHES 4   /* Return list of patches of a program (parm1) */
+#define PM_GET_PATCH   5       /* Return patch header of patch parm1 */
+#define PM_SET_PATCH   6       /* Set patch header of patch parm1 */
+#define PM_READ_PATCH  7       /* Read patch (wave) data */
+#define PM_WRITE_PATCH 8       /* Write patch (wave) data */
+
+/*
+ * Commands 0x1000 to 0xffff are for communication between the patch manager
+ * and the client
+ */
+#define _PM_LOAD_PATCH 0x100
+
+/*
+ * Commands above 0xffff reserved for device specific use
+ */
+
+       long parm1;
+       long parm2;
+       long parm3;
+
+       union {
+               u_char data8[4000];
+               u_short data16[2000];
+               u_long data32[1000];
+               struct patch_info patch;
+       } data;
+};
+
+/*
+ * When a patch manager daemon is present, it will be informed by the
+ * driver when something important happens. For example when the
+ * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is
+ * returned. The command field contains the event type:
+ */
+#define PM_E_OPENED            1       /* /dev/sequencer opened */
+#define PM_E_CLOSED            2       /* /dev/sequencer closed */
+#define PM_E_PATCH_RESET       3       /* SNDCTL_RESETSAMPLES called */
+#define PM_E_PATCH_LOADED      4       /* A patch has been loaded by appl */
+
+/*
+ * /dev/sequencer input events.
+ *
+ * The data written to the /dev/sequencer is a stream of events. Events
+ * are records of 4 or 8 bytes. The first byte defines the size.
+ * Any number of events can be written with a write call. There
+ * is a set of macros for sending these events. Use these macros if you
+ * want to maximize portability of your program.
+ *
+ * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
+ * (All input events are currently 4 bytes long. Be prepared to support
+ * 8 byte events also. If you receive any event having first byte >= 128,
+ * it's a 8 byte event.
+ *
+ * The events are documented at the end of this file.
+ *
+ * Normal events (4 bytes)
+ * There is also a 8 byte version of most of the 4 byte events. The
+ * 8 byte one is recommended.
+ */
+#define SEQ_NOTEOFF            0
+#define SEQ_FMNOTEOFF          SEQ_NOTEOFF     /* Just old name */
+#define SEQ_NOTEON             1
+#define        SEQ_FMNOTEON            SEQ_NOTEON
+#define SEQ_WAIT               TMR_WAIT_ABS
+#define SEQ_PGMCHANGE          3
+#define SEQ_FMPGMCHANGE                SEQ_PGMCHANGE
+#define SEQ_SYNCTIMER          TMR_START
+#define SEQ_MIDIPUTC           5
+#define SEQ_DRUMON             6       /*** OBSOLETE ***/
+#define SEQ_DRUMOFF            7       /*** OBSOLETE ***/
+#define SEQ_ECHO               TMR_ECHO        /* For synching programs with output */
+#define SEQ_AFTERTOUCH         9
+#define SEQ_CONTROLLER         10
+
+/*
+ *     Midi controller numbers
+ *
+ * Controllers 0 to 31 (0x00 to 0x1f) and 32 to 63 (0x20 to 0x3f)
+ * are continuous controllers.
+ * In the MIDI 1.0 these controllers are sent using two messages.
+ * Controller numbers 0 to 31 are used to send the MSB and the
+ * controller numbers 32 to 63 are for the LSB. Note that just 7 bits
+ * are used in MIDI bytes.
+ */
+
+#define        CTL_BANK_SELECT         0x00
+#define        CTL_MODWHEEL            0x01
+#define CTL_BREATH             0x02
+/*     undefined               0x03 */
+#define CTL_FOOT               0x04
+#define CTL_PORTAMENTO_TIME    0x05
+#define CTL_DATA_ENTRY         0x06
+#define CTL_MAIN_VOLUME                0x07
+#define CTL_BALANCE            0x08
+/*     undefined               0x09 */
+#define CTL_PAN                        0x0a
+#define CTL_EXPRESSION         0x0b
+/*     undefined               0x0c - 0x0f */
+#define CTL_GENERAL_PURPOSE1   0x10
+#define CTL_GENERAL_PURPOSE2   0x11
+#define CTL_GENERAL_PURPOSE3   0x12
+#define CTL_GENERAL_PURPOSE4   0x13
+/*     undefined               0x14 - 0x1f */
+
+/*     undefined               0x20 */
+
+/*
+ * The controller numbers 0x21 to 0x3f are reserved for the
+ * least significant bytes of the controllers 0x00 to 0x1f.
+ * These controllers are not recognised by the driver.
+ *
+ * Controllers 64 to 69 (0x40 to 0x45) are on/off switches.
+ * 0=OFF and 127=ON (intermediate values are possible)
+ */
+#define CTL_DAMPER_PEDAL       0x40
+#define CTL_SUSTAIN            CTL_DAMPER_PEDAL        /* Alias */
+#define CTL_HOLD               CTL_DAMPER_PEDAL        /* Alias */
+#define CTL_PORTAMENTO         0x41
+#define CTL_SOSTENUTO          0x42
+#define CTL_SOFT_PEDAL         0x43
+/*     undefined               0x44 */
+#define CTL_HOLD2              0x45
+/*     undefined               0x46 - 0x4f */
+
+#define CTL_GENERAL_PURPOSE5   0x50
+#define CTL_GENERAL_PURPOSE6   0x51
+#define CTL_GENERAL_PURPOSE7   0x52
+#define CTL_GENERAL_PURPOSE8   0x53
+/*     undefined               0x54 - 0x5a */
+#define CTL_EXT_EFF_DEPTH      0x5b
+#define CTL_TREMOLO_DEPTH      0x5c
+#define CTL_CHORUS_DEPTH       0x5d
+#define CTL_DETUNE_DEPTH       0x5e
+#define CTL_CELESTE_DEPTH      CTL_DETUNE_DEPTH /* Alias for the above one */
+#define CTL_PHASER_DEPTH       0x5f
+#define CTL_DATA_INCREMENT     0x60
+#define CTL_DATA_DECREMENT     0x61
+#define CTL_NONREG_PARM_NUM_LSB        0x62
+#define CTL_NONREG_PARM_NUM_MSB        0x63
+#define CTL_REGIST_PARM_NUM_LSB        0x64
+#define CTL_REGIST_PARM_NUM_MSB        0x65
+/*     undefined               0x66 - 0x78 */
+/*     reserved                0x79 - 0x7f */
+
+/* Pseudo controllers (not midi compatible) */
+#define CTRL_PITCH_BENDER      255
+#define CTRL_PITCH_BENDER_RANGE        254
+#define CTRL_EXPRESSION                253     /* Obsolete */
+#define CTRL_MAIN_VOLUME       252     /* Obsolete */
+
+#define SEQ_BALANCE            11
+#define SEQ_VOLMODE             12
+
+/*
+ * Volume mode decides how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO      1
+#define VOL_METHOD_LINEAR      2
+
+/*
+ * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
+ *      input events.
+ */
+
+/*
+ * Event codes 0xf0 to 0xfc are reserved for future extensions.
+ */
+
+#define SEQ_FULLSIZE           0xfd    /* Long events */
+/*
+ * SEQ_FULLSIZE events are used for loading patches/samples to the
+ * synthesizer devices. These events are passed directly to the driver
+ * of the associated synthesizer device. There is no limit to the size
+ * of the extended events. These events are not queued but executed
+ * immediately when the write() is called (execution can take several
+ * seconds of time).
+ *
+ * When a SEQ_FULLSIZE message is written to the device, it must
+ * be written using exactly one write() call. Other events cannot
+ * be mixed to the same write.
+ *
+ * For FM synths (YM3812/OPL3) use struct sbi_instrument and write
+ * it to the /dev/sequencer. Don't write other data together with
+ * the instrument structure Set the key field of the structure to
+ * FM_PATCH. The device field is used to route the patch to the
+ * corresponding device.
+ *
+ * For Gravis UltraSound use struct patch_info. Initialize the key field
+ * to GUS_PATCH.
+ */
+#define SEQ_PRIVATE    0xfe    /* Low level HW dependent events (8 bytes) */
+#define SEQ_EXTENDED   0xff    /* Extended events (8 bytes) OBSOLETE */
+
+/*
+ * Record for FM patches
+ */
+
+typedef u_char sbi_instr_data[32];
+
+struct sbi_instrument {
+       u_short key;    /* FM_PATCH or OPL3_PATCH */
+#define FM_PATCH       _PATCHKEY(0x01)
+#define OPL3_PATCH     _PATCHKEY(0x03)
+       short           device;         /* Synth# (0-4) */
+       int             channel;        /* Program# to be initialized  */
+       sbi_instr_data  operators;      /* Reg. settings for operator cells
+                                        * (.SBI format)        */
+};
+
+struct synth_info {    /* Read only */
+       char    name[30];
+       int     device;         /* 0-N. INITIALIZE BEFORE CALLING */
+       int     synth_type;
+#define SYNTH_TYPE_FM                  0
+#define SYNTH_TYPE_SAMPLE              1
+#define SYNTH_TYPE_MIDI                        2       /* Midi interface */
+
+       int     synth_subtype;
+#define FM_TYPE_ADLIB                  0x00
+#define FM_TYPE_OPL3                   0x01
+#define MIDI_TYPE_MPU401               0x401
+
+#define SAMPLE_TYPE_BASIC              0x10
+#define SAMPLE_TYPE_GUS                        SAMPLE_TYPE_BASIC
+#define SAMPLE_TYPE_AWE32              0x20
+
+       int     perc_mode;      /* No longer supported */
+       int     nr_voices;
+       int     nr_drums;       /* Obsolete field */
+       int     instr_bank_size;
+       u_long  capabilities;
+#define SYNTH_CAP_PERCMODE     0x00000001 /* No longer used */
+#define SYNTH_CAP_OPL3         0x00000002 /* Set if OPL3 supported */
+#define SYNTH_CAP_INPUT                0x00000004 /* Input (MIDI) device */
+       int     dummies[19];    /* Reserve space */
+};
+
+struct sound_timer_info {
+       char name[32];
+       int caps;
+};
+
+struct midi_info {
+       char            name[30];
+       int             device;         /* 0-N. INITIALIZE BEFORE CALLING */
+       u_long  capabilities;   /* To be defined later */
+       int             dev_type;
+       int             dummies[18];    /* Reserve space */
+};
+
+/*
+ * ioctl commands for the /dev/midi##
+ */
+typedef struct {
+       u_char cmd;
+       char nr_args, nr_returns;
+       u_char data[30];
+} mpu_command_rec;
+
+#define SNDCTL_MIDI_PRETIME    _IOWR('m', 0, int)
+#define SNDCTL_MIDI_MPUMODE    _IOWR('m', 1, int)
+#define SNDCTL_MIDI_MPUCMD     _IOWR('m', 2, mpu_command_rec)
+#define MIOSPASSTHRU           _IOWR('m', 3, int)
+#define MIOGPASSTHRU           _IOWR('m', 4, int)
+
+/*
+ * IOCTL commands for /dev/dsp and /dev/audio
+ */
+
+#define SNDCTL_DSP_RESET       _IO  ('P', 0)
+#define SNDCTL_DSP_SYNC                _IO  ('P', 1)
+#define SNDCTL_DSP_SPEED       _IOWR('P', 2, int)
+#define SNDCTL_DSP_STEREO      _IOWR('P', 3, int)
+#define SNDCTL_DSP_GETBLKSIZE  _IOR('P', 4, int)
+#define SNDCTL_DSP_SETBLKSIZE   _IOW('P', 4, int)
+#define SNDCTL_DSP_SETFMT      _IOWR('P',5, int) /* Selects ONE fmt*/
+
+/*
+ * SOUND_PCM_WRITE_CHANNELS is not that different
+ * from SNDCTL_DSP_STEREO
+ */
+#define SOUND_PCM_WRITE_CHANNELS       _IOWR('P', 6, int)
+#define SNDCTL_DSP_CHANNELS    SOUND_PCM_WRITE_CHANNELS
+#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
+#define SNDCTL_DSP_POST                _IO  ('P', 8)
+
+/*
+ * SNDCTL_DSP_SETBLKSIZE and the following two calls mostly do
+ * the same thing, i.e. set the block size used in DMA transfers.
+ */
+#define SNDCTL_DSP_SUBDIVIDE   _IOWR('P', 9, int)
+#define SNDCTL_DSP_SETFRAGMENT _IOWR('P',10, int)
+
+
+#define SNDCTL_DSP_GETFMTS     _IOR ('P',11, int) /* Returns a mask */
+/*
+ * Buffer status queries.
+ */
+typedef struct audio_buf_info {
+    int fragments;     /* # of avail. frags (partly used ones not counted) */
+    int fragstotal;    /* Total # of fragments allocated */
+    int fragsize;      /* Size of a fragment in bytes */
+
+    int bytes; /* Avail. space in bytes (includes partly used fragments) */
+               /* Note! 'bytes' could be more than fragments*fragsize */
+} audio_buf_info;
+
+#define SNDCTL_DSP_GETOSPACE   _IOR ('P',12, audio_buf_info)
+#define SNDCTL_DSP_GETISPACE   _IOR ('P',13, audio_buf_info)
+
+/*
+ * SNDCTL_DSP_NONBLOCK is the same (but less powerful, since the
+ * action cannot be undone) of FIONBIO. The same can be achieved
+ * by opening the device with O_NDELAY
+ */
+#define SNDCTL_DSP_NONBLOCK    _IO  ('P',14)
+
+#define SNDCTL_DSP_GETCAPS     _IOR ('P',15, int)
+#define DSP_CAP_REVISION       0x000000ff /* revision level (0 to 255) */
+#define DSP_CAP_DUPLEX         0x00000100 /* Full duplex record/playback */
+#define DSP_CAP_REALTIME       0x00000200 /* Real time capability */
+#define DSP_CAP_BATCH          0x00000400
+    /*
+     * Device has some kind of internal buffers which may
+     * cause some delays and decrease precision of timing
+     */
+#define DSP_CAP_COPROC         0x00000800
+    /* Has a coprocessor, sometimes it's a DSP but usually not */
+#define DSP_CAP_TRIGGER                0x00001000 /* Supports SETTRIGGER */
+#define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */
+
+/*
+ * What do these function do ?
+ */
+#define SNDCTL_DSP_GETTRIGGER  _IOR ('P',16, int)
+#define SNDCTL_DSP_SETTRIGGER  _IOW ('P',16, int)
+#define PCM_ENABLE_INPUT       0x00000001
+#define PCM_ENABLE_OUTPUT      0x00000002
+
+typedef struct count_info {
+       int bytes;      /* Total # of bytes processed */
+       int blocks;     /* # of fragment transitions since last time */
+       int ptr;        /* Current DMA pointer value */
+} count_info;
+
+/*
+ * GETIPTR and GETISPACE are not that different... same for out.
+ */
+#define SNDCTL_DSP_GETIPTR     _IOR ('P',17, count_info)
+#define SNDCTL_DSP_GETOPTR     _IOR ('P',18, count_info)
+
+typedef struct buffmem_desc {
+       caddr_t buffer;
+       int size;
+} buffmem_desc;
+
+#define SNDCTL_DSP_MAPINBUF    _IOR ('P', 19, buffmem_desc)
+#define SNDCTL_DSP_MAPOUTBUF   _IOR ('P', 20, buffmem_desc)
+#define SNDCTL_DSP_SETSYNCRO   _IO  ('P', 21)
+#define SNDCTL_DSP_SETDUPLEX   _IO  ('P', 22)
+#define SNDCTL_DSP_GETODELAY   _IOR ('P', 23, int)
+
+/*
+ * I guess these are the readonly version of the same
+ * functions that exist above as SNDCTL_DSP_...
+ */
+#define SOUND_PCM_READ_RATE    _IOR ('P', 2, int)
+#define SOUND_PCM_READ_CHANNELS        _IOR ('P', 6, int)
+#define SOUND_PCM_READ_BITS    _IOR ('P', 5, int)
+#define SOUND_PCM_READ_FILTER  _IOR ('P', 7, int)
+
+/*
+ * ioctl calls to be used in communication with coprocessors and
+ * DSP chips.
+ */
+
+typedef struct copr_buffer {
+       int command;    /* Set to 0 if not used */
+       int flags;
+#define CPF_NONE               0x0000
+#define CPF_FIRST              0x0001  /* First block */
+#define CPF_LAST               0x0002  /* Last block */
+       int len;
+       int offs;       /* If required by the device (0 if not used) */
+
+       u_char data[4000]; /* NOTE! 4000 is not 4k */
+} copr_buffer;
+
+typedef struct copr_debug_buf {
+       int command;    /* Used internally. Set to 0 */
+       int parm1;
+       int parm2;
+       int flags;
+       int len;        /* Length of data in bytes */
+} copr_debug_buf;
+
+typedef struct copr_msg {
+       int len;
+       u_char data[4000];
+} copr_msg;
+
+#define SNDCTL_COPR_RESET       _IO  ('C',  0)
+#define SNDCTL_COPR_LOAD       _IOWR('C',  1, copr_buffer)
+#define SNDCTL_COPR_RDATA      _IOWR('C',  2, copr_debug_buf)
+#define SNDCTL_COPR_RCODE      _IOWR('C',  3, copr_debug_buf)
+#define SNDCTL_COPR_WDATA      _IOW ('C',  4, copr_debug_buf)
+#define SNDCTL_COPR_WCODE      _IOW ('C',  5, copr_debug_buf)
+#define SNDCTL_COPR_RUN                _IOWR('C',  6, copr_debug_buf)
+#define SNDCTL_COPR_HALT       _IOWR('C',  7, copr_debug_buf)
+#define SNDCTL_COPR_SENDMSG    _IOW ('C',  8, copr_msg)
+#define SNDCTL_COPR_RCVMSG     _IOR ('C',  9, copr_msg)
+
+/*
+ * IOCTL commands for /dev/mixer
+ */
+
+/*
+ * Mixer devices
+ *
+ * There can be up to 20 different analog mixer channels. The
+ * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
+ * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
+ * the devices supported by the particular mixer.
+ */
+
+#define SOUND_MIXER_NRDEVICES  25
+#define SOUND_MIXER_VOLUME     0       /* Master output level */
+#define SOUND_MIXER_BASS       1       /* Treble level of all output channels */
+#define SOUND_MIXER_TREBLE     2       /* Bass level of all output channels */
+#define SOUND_MIXER_SYNTH      3       /* Volume of synthesier input */
+#define SOUND_MIXER_PCM                4       /* Output level for the audio device */
+#define SOUND_MIXER_SPEAKER    5       /* Output level for the PC speaker
+                                        * signals */
+#define SOUND_MIXER_LINE       6       /* Volume level for the line in jack */
+#define SOUND_MIXER_MIC                7       /* Volume for the signal coming from
+                                        * the microphone jack */
+#define SOUND_MIXER_CD         8       /* Volume level for the input signal
+                                        * connected to the CD audio input */
+#define SOUND_MIXER_IMIX       9       /* Recording monitor. It controls the
+                                        * output volume of the selected
+                                        * recording sources while recording */
+#define SOUND_MIXER_ALTPCM     10      /* Volume of the alternative codec
+                                        * device */
+#define SOUND_MIXER_RECLEV     11      /* Global recording level */
+#define SOUND_MIXER_IGAIN      12      /* Input gain */
+#define SOUND_MIXER_OGAIN      13      /* Output gain */
+/*
+ * The AD1848 codec and compatibles have three line level inputs
+ * (line, aux1 and aux2). Since each card manufacturer have assigned
+ * different meanings to these inputs, it's inpractical to assign
+ * specific meanings (line, cd, synth etc.) to them.
+ */
+#define SOUND_MIXER_LINE1      14      /* Input source 1  (aux1) */
+#define SOUND_MIXER_LINE2      15      /* Input source 2  (aux2) */
+#define SOUND_MIXER_LINE3      16      /* Input source 3  (line) */
+#define SOUND_MIXER_DIGITAL1    17      /* Digital (input) 1 */
+#define SOUND_MIXER_DIGITAL2    18      /* Digital (input) 2 */
+#define SOUND_MIXER_DIGITAL3    19      /* Digital (input) 3 */
+#define SOUND_MIXER_PHONEIN     20      /* Phone input */
+#define SOUND_MIXER_PHONEOUT    21      /* Phone output */
+#define SOUND_MIXER_VIDEO       22      /* Video/TV (audio) in */
+#define SOUND_MIXER_RADIO       23      /* Radio in */
+#define SOUND_MIXER_MONITOR     24      /* Monitor (usually mic) volume */
+
+
+/*
+ * Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX)
+ * Not counted to SOUND_MIXER_NRDEVICES, but use the same number space
+ */
+#define SOUND_ONOFF_MIN                28
+#define SOUND_ONOFF_MAX                30
+#define SOUND_MIXER_MUTE       28      /* 0 or 1 */
+#define SOUND_MIXER_ENHANCE    29      /* Enhanced stereo (0, 40, 60 or 80) */
+#define SOUND_MIXER_LOUD       30      /* 0 or 1 */
+
+/* Note!       Number 31 cannot be used since the sign bit is reserved */
+#define SOUND_MIXER_NONE        31
+
+#define SOUND_DEVICE_LABELS    { \
+       "Vol  ", "Bass ", "Trebl", "Synth", "Pcm  ", "Spkr ", "Line ", \
+       "Mic  ", "CD   ", "Mix  ", "Pcm2 ", "Rec  ", "IGain", "OGain", \
+       "Line1", "Line2", "Line3", "Digital1", "Digital2", "Digital3", \
+       "PhoneIn", "PhoneOut", "Video", "Radio", "Monitor"}
+
+#define SOUND_DEVICE_NAMES     { \
+       "vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+       "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
+       "line1", "line2", "line3", "dig1", "dig2", "dig3", \
+       "phin", "phout", "video", "radio", "monitor"}
+
+/*     Device bitmask identifiers      */
+
+#define SOUND_MIXER_RECSRC     0xff    /* 1 bit per recording source */
+#define SOUND_MIXER_DEVMASK    0xfe    /* 1 bit per supported device */
+#define SOUND_MIXER_RECMASK    0xfd    /* 1 bit per supp. recording source */
+#define SOUND_MIXER_CAPS       0xfc
+#define SOUND_CAP_EXCL_INPUT   0x00000001      /* Only 1 rec. src at a time */
+#define SOUND_MIXER_STEREODEVS 0xfb    /* Mixer channels supporting stereo */
+
+/*     Device mask bits        */
+
+#define SOUND_MASK_VOLUME      (1 << SOUND_MIXER_VOLUME)
+#define SOUND_MASK_BASS                (1 << SOUND_MIXER_BASS)
+#define SOUND_MASK_TREBLE      (1 << SOUND_MIXER_TREBLE)
+#define SOUND_MASK_SYNTH       (1 << SOUND_MIXER_SYNTH)
+#define SOUND_MASK_PCM         (1 << SOUND_MIXER_PCM)
+#define SOUND_MASK_SPEAKER     (1 << SOUND_MIXER_SPEAKER)
+#define SOUND_MASK_LINE                (1 << SOUND_MIXER_LINE)
+#define SOUND_MASK_MIC         (1 << SOUND_MIXER_MIC)
+#define SOUND_MASK_CD          (1 << SOUND_MIXER_CD)
+#define SOUND_MASK_IMIX                (1 << SOUND_MIXER_IMIX)
+#define SOUND_MASK_ALTPCM      (1 << SOUND_MIXER_ALTPCM)
+#define SOUND_MASK_RECLEV      (1 << SOUND_MIXER_RECLEV)
+#define SOUND_MASK_IGAIN       (1 << SOUND_MIXER_IGAIN)
+#define SOUND_MASK_OGAIN       (1 << SOUND_MIXER_OGAIN)
+#define SOUND_MASK_LINE1       (1 << SOUND_MIXER_LINE1)
+#define SOUND_MASK_LINE2       (1 << SOUND_MIXER_LINE2)
+#define SOUND_MASK_LINE3       (1 << SOUND_MIXER_LINE3)
+#define SOUND_MASK_DIGITAL1     (1 << SOUND_MIXER_DIGITAL1)
+#define SOUND_MASK_DIGITAL2     (1 << SOUND_MIXER_DIGITAL2)
+#define SOUND_MASK_DIGITAL3     (1 << SOUND_MIXER_DIGITAL3)
+#define SOUND_MASK_PHONEIN      (1 << SOUND_MIXER_PHONEIN)
+#define SOUND_MASK_PHONEOUT     (1 << SOUND_MIXER_PHONEOUT)
+#define SOUND_MASK_RADIO        (1 << SOUND_MIXER_RADIO)
+#define SOUND_MASK_VIDEO        (1 << SOUND_MIXER_VIDEO)
+#define SOUND_MASK_MONITOR      (1 << SOUND_MIXER_MONITOR)
+
+/* Obsolete macros */
+#define SOUND_MASK_MUTE                (1 << SOUND_MIXER_MUTE)
+#define SOUND_MASK_ENHANCE     (1 << SOUND_MIXER_ENHANCE)
+#define SOUND_MASK_LOUD                (1 << SOUND_MIXER_LOUD)
+
+#define MIXER_READ(dev)                _IOR('M', dev, int)
+#define SOUND_MIXER_READ_VOLUME                MIXER_READ(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_READ_BASS          MIXER_READ(SOUND_MIXER_BASS)
+#define SOUND_MIXER_READ_TREBLE                MIXER_READ(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_READ_SYNTH         MIXER_READ(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_READ_PCM           MIXER_READ(SOUND_MIXER_PCM)
+#define SOUND_MIXER_READ_SPEAKER       MIXER_READ(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_READ_LINE          MIXER_READ(SOUND_MIXER_LINE)
+#define SOUND_MIXER_READ_MIC           MIXER_READ(SOUND_MIXER_MIC)
+#define SOUND_MIXER_READ_CD            MIXER_READ(SOUND_MIXER_CD)
+#define SOUND_MIXER_READ_IMIX          MIXER_READ(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_READ_ALTPCM                MIXER_READ(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_READ_RECLEV                MIXER_READ(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_READ_IGAIN         MIXER_READ(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_READ_OGAIN         MIXER_READ(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_READ_LINE1         MIXER_READ(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_READ_LINE2         MIXER_READ(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_READ_LINE3         MIXER_READ(SOUND_MIXER_LINE3)
+#define SOUND_MIXER_READ_DIGITAL1      MIXER_READ(SOUND_MIXER_DIGITAL1)
+#define SOUND_MIXER_READ_DIGITAL2      MIXER_READ(SOUND_MIXER_DIGITAL2)
+#define SOUND_MIXER_READ_DIGITAL3      MIXER_READ(SOUND_MIXER_DIGITAL3)
+#define SOUND_MIXER_READ_PHONEIN       MIXER_READ(SOUND_MIXER_PHONEIN)
+#define SOUND_MIXER_READ_PHONEOUT      MIXER_READ(SOUND_MIXER_PHONEOUT)
+#define SOUND_MIXER_READ_RADIO         MIXER_READ(SOUND_MIXER_RADIO)
+#define SOUND_MIXER_READ_VIDEO         MIXER_READ(SOUND_MIXER_VIDEO)
+#define SOUND_MIXER_READ_MONITOR       MIXER_READ(SOUND_MIXER_MONITOR)
+
+/* Obsolete macros */
+#define SOUND_MIXER_READ_MUTE          MIXER_READ(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_READ_ENHANCE       MIXER_READ(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_READ_LOUD          MIXER_READ(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_READ_RECSRC                MIXER_READ(SOUND_MIXER_RECSRC)
+#define SOUND_MIXER_READ_DEVMASK       MIXER_READ(SOUND_MIXER_DEVMASK)
+#define SOUND_MIXER_READ_RECMASK       MIXER_READ(SOUND_MIXER_RECMASK)
+#define SOUND_MIXER_READ_STEREODEVS    MIXER_READ(SOUND_MIXER_STEREODEVS)
+#define SOUND_MIXER_READ_CAPS          MIXER_READ(SOUND_MIXER_CAPS)
+
+#define MIXER_WRITE(dev)               _IOWR('M', dev, int)
+#define SOUND_MIXER_WRITE_VOLUME       MIXER_WRITE(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_WRITE_BASS         MIXER_WRITE(SOUND_MIXER_BASS)
+#define SOUND_MIXER_WRITE_TREBLE       MIXER_WRITE(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_WRITE_SYNTH                MIXER_WRITE(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_WRITE_PCM          MIXER_WRITE(SOUND_MIXER_PCM)
+#define SOUND_MIXER_WRITE_SPEAKER      MIXER_WRITE(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_WRITE_LINE         MIXER_WRITE(SOUND_MIXER_LINE)
+#define SOUND_MIXER_WRITE_MIC          MIXER_WRITE(SOUND_MIXER_MIC)
+#define SOUND_MIXER_WRITE_CD           MIXER_WRITE(SOUND_MIXER_CD)
+#define SOUND_MIXER_WRITE_IMIX         MIXER_WRITE(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_WRITE_ALTPCM       MIXER_WRITE(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_WRITE_RECLEV       MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_WRITE_IGAIN                MIXER_WRITE(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_WRITE_OGAIN                MIXER_WRITE(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_WRITE_LINE1                MIXER_WRITE(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_WRITE_LINE2                MIXER_WRITE(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_WRITE_LINE3                MIXER_WRITE(SOUND_MIXER_LINE3)
+#define SOUND_MIXER_WRITE_DIGITAL1     MIXER_WRITE(SOUND_MIXER_DIGITAL1)
+#define SOUND_MIXER_WRITE_DIGITAL2     MIXER_WRITE(SOUND_MIXER_DIGITAL2)
+#define SOUND_MIXER_WRITE_DIGITAL3     MIXER_WRITE(SOUND_MIXER_DIGITAL3)
+#define SOUND_MIXER_WRITE_PHONEIN              MIXER_WRITE(SOUND_MIXER_PHONEIN)
+#define SOUND_MIXER_WRITE_PHONEOUT     MIXER_WRITE(SOUND_MIXER_PHONEOUT)
+#define SOUND_MIXER_WRITE_RADIO                MIXER_WRITE(SOUND_MIXER_RADIO)
+#define SOUND_MIXER_WRITE_VIDEO                MIXER_WRITE(SOUND_MIXER_VIDEO)
+#define SOUND_MIXER_WRITE_MONITOR      MIXER_WRITE(SOUND_MIXER_MONITOR)
+
+#define SOUND_MIXER_WRITE_MUTE         MIXER_WRITE(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_WRITE_ENHANCE      MIXER_WRITE(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_WRITE_LOUD         MIXER_WRITE(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_WRITE_RECSRC       MIXER_WRITE(SOUND_MIXER_RECSRC)
+
+typedef struct mixer_info {
+  char id[16];
+  char name[32];
+  int  modify_counter;
+  int fillers[10];
+} mixer_info;
+
+#define SOUND_MIXER_INFO               _IOR('M', 101, mixer_info)
+
+#define LEFT_CHN       0
+#define RIGHT_CHN      1
+
+/*
+ * Level 2 event types for /dev/sequencer
+ */
+
+/*
+ * The 4 most significant bits of byte 0 specify the class of
+ * the event:
+ *
+ *     0x8X = system level events,
+ *     0x9X = device/port specific events, event[1] = device/port,
+ *             The last 4 bits give the subtype:
+ *                     0x02    = Channel event (event[3] = chn).
+ *                     0x01    = note event (event[4] = note).
+ *                     (0x01 is not used alone but always with bit 0x02).
+ *            event[2] = MIDI message code (0x80=note off etc.)
+ *
+ */
+
+#define EV_SEQ_LOCAL           0x80
+#define EV_TIMING              0x81
+#define EV_CHN_COMMON          0x92
+#define EV_CHN_VOICE           0x93
+#define EV_SYSEX               0x94
+/*
+ * Event types 200 to 220 are reserved for application use.
+ * These numbers will not be used by the driver.
+ */
+
+/*
+ * Events for event type EV_CHN_VOICE
+ */
+
+#define MIDI_NOTEOFF           0x80
+#define MIDI_NOTEON            0x90
+#define MIDI_KEY_PRESSURE      0xA0
+
+/*
+ * Events for event type EV_CHN_COMMON
+ */
+
+#define MIDI_CTL_CHANGE                0xB0
+#define MIDI_PGM_CHANGE                0xC0
+#define MIDI_CHN_PRESSURE      0xD0
+#define MIDI_PITCH_BEND                0xE0
+
+#define MIDI_SYSTEM_PREFIX     0xF0
+
+/*
+ * Timer event types
+ */
+#define TMR_WAIT_REL           1       /* Time relative to the prev time */
+#define TMR_WAIT_ABS           2       /* Absolute time since TMR_START */
+#define TMR_STOP               3
+#define TMR_START              4
+#define TMR_CONTINUE           5
+#define TMR_TEMPO              6
+#define TMR_ECHO               8
+#define TMR_CLOCK              9       /* MIDI clock */
+#define TMR_SPP                        10      /* Song position pointer */
+#define TMR_TIMESIG            11      /* Time signature */
+
+/*
+ *     Local event types
+ */
+#define LOCL_STARTAUDIO                1
+
+#if (!defined(_KERNEL) && !defined(INKERNEL)) || defined(USE_SEQ_MACROS)
+/*
+ *     Some convenience macros to simplify programming of the
+ *     /dev/sequencer interface
+ *
+ *     These macros define the API which should be used when possible.
+ */
+
+#ifndef USE_SIMPLE_MACROS
+void seqbuf_dump(void);        /* This function must be provided by programs */
+
+/* Sample seqbuf_dump() implementation:
+ *
+ *     SEQ_DEFINEBUF (2048);   -- Defines a buffer for 2048 bytes
+ *
+ *     int seqfd;              -- The file descriptor for /dev/sequencer.
+ *
+ *     void
+ *     seqbuf_dump ()
+ *     {
+ *       if (_seqbufptr)
+ *         if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ *           {
+ *             perror ("write /dev/sequencer");
+ *             exit (-1);
+ *           }
+ *       _seqbufptr = 0;
+ *     }
+ */
+
+#define SEQ_DEFINEBUF(len)             \
+       u_char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define SEQ_USE_EXTBUF()               \
+       extern u_char _seqbuf[]; \
+       extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_DECLAREBUF()               SEQ_USE_EXTBUF()
+#define SEQ_PM_DEFINES                 struct patmgr_info _pm_info
+#define _SEQ_NEEDBUF(len)              \
+       if ((_seqbufptr+(len)) > _seqbuflen) \
+               seqbuf_dump()
+#define _SEQ_ADVBUF(len)               _seqbufptr += len
+#define SEQ_DUMPBUF                    seqbuf_dump
+#else
+/*
+ * This variation of the sequencer macros is used just to format one event
+ * using fixed buffer.
+ *
+ * The program using the macro library must define the following macros before
+ * using this library.
+ *
+ * #define _seqbuf              name of the buffer (u_char[])
+ * #define _SEQ_ADVBUF(len)     If the applic needs to know the exact
+ *                              size of the event, this macro can be used.
+ *                              Otherwise this must be defined as empty.
+ * #define _seqbufptr           Define the name of index variable or 0 if
+ *                              not required.
+ */
+#define _SEQ_NEEDBUF(len)      /* empty */
+#endif
+
+#define PM_LOAD_PATCH(dev, bank, pgm)  \
+       (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+       _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
+       _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
+       ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define PM_LOAD_PATCHES(dev, bank, pgm) \
+       (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+       _pm_info.device=dev, bcopy( pgm, _pm_info.data.data8,  128), \
+       _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
+       ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+
+#define SEQ_VOLUME_MODE(dev, mode)     { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+       _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+       _seqbuf[_seqbufptr+2] = (dev);\
+       _seqbuf[_seqbufptr+3] = (mode);\
+       _seqbuf[_seqbufptr+4] = 0;\
+       _seqbuf[_seqbufptr+5] = 0;\
+       _seqbuf[_seqbufptr+6] = 0;\
+       _seqbuf[_seqbufptr+7] = 0;\
+       _SEQ_ADVBUF(8);}
+
+/*
+ * Midi voice messages
+ */
+
+#define _CHN_VOICE(dev, event, chn, note, parm)  { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+       _seqbuf[_seqbufptr+1] = (dev);\
+       _seqbuf[_seqbufptr+2] = (event);\
+       _seqbuf[_seqbufptr+3] = (chn);\
+       _seqbuf[_seqbufptr+4] = (note);\
+       _seqbuf[_seqbufptr+5] = (parm);\
+       _seqbuf[_seqbufptr+6] = (0);\
+       _seqbuf[_seqbufptr+7] = 0;\
+       _SEQ_ADVBUF(8);}
+
+#define SEQ_START_NOTE(dev, chn, note, vol) \
+               _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
+
+#define SEQ_STOP_NOTE(dev, chn, note, vol) \
+               _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol)
+
+#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \
+               _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure)
+
+/*
+ * Midi channel messages
+ */
+
+#define _CHN_COMMON(dev, event, chn, p1, p2, w14) { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr] = EV_CHN_COMMON;\
+       _seqbuf[_seqbufptr+1] = (dev);\
+       _seqbuf[_seqbufptr+2] = (event);\
+       _seqbuf[_seqbufptr+3] = (chn);\
+       _seqbuf[_seqbufptr+4] = (p1);\
+       _seqbuf[_seqbufptr+5] = (p2);\
+       *(short *)&_seqbuf[_seqbufptr+6] = (w14);\
+       _SEQ_ADVBUF(8);}
+/*
+ * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits
+ * sending any MIDI bytes but it's absolutely not possible. Trying to do
+ * so _will_ cause problems with MPU401 intelligent mode).
+ *
+ * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
+ * sent by calling SEQ_SYSEX() several times (there must be no other events
+ * between them). First sysex fragment must have 0xf0 in the first byte
+ * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
+ * between these sysex start and end markers cannot be larger than 0x7f. Also
+ * lengths of each fragments (except the last one) must be 6.
+ *
+ * Breaking the above rules may work with some MIDI ports but is likely to
+ * cause fatal problems with some other devices (such as MPU401).
+ */
+#define SEQ_SYSEX(dev, buf, len) { \
+       int i, l=(len); if (l>6)l=6;\
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr] = EV_SYSEX;\
+       for(i=0;i<l;i++)_seqbuf[_seqbufptr+i+1] = (buf)[i];\
+       for(i=l;i<6;i++)_seqbuf[_seqbufptr+i+1] = 0xff;\
+       _SEQ_ADVBUF(8);}
+
+#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
+       _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+
+#define SEQ_SET_PATCH(dev, chn, patch) \
+       _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0)
+
+#define SEQ_CONTROL(dev, chn, controller, value) \
+       _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
+
+#define SEQ_BENDER(dev, chn, value) \
+       _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+
+#define SEQ_V2_X_CONTROL(dev, voice, controller, value)        { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+       _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+       _seqbuf[_seqbufptr+2] = (dev);\
+       _seqbuf[_seqbufptr+3] = (voice);\
+       _seqbuf[_seqbufptr+4] = (controller);\
+       *(short *)&_seqbuf[_seqbufptr+5] = (value);\
+       _seqbuf[_seqbufptr+7] = 0;\
+       _SEQ_ADVBUF(8);}
+
+/*
+ * The following 5 macros are incorrectly implemented and obsolete.
+ * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
+ */
+
+#define SEQ_PITCHBEND(dev, voice, value) \
+       SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) \
+       SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) \
+       SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) \
+       SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) \
+       SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
+
+/*
+ * Timing and syncronization macros
+ */
+
+#define _TIMER_EVENT(ev, parm)         { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr+0] = EV_TIMING; \
+       _seqbuf[_seqbufptr+1] = (ev); \
+       _seqbuf[_seqbufptr+2] = 0;\
+       _seqbuf[_seqbufptr+3] = 0;\
+       *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+       _SEQ_ADVBUF(8); \
+       }
+
+#define SEQ_START_TIMER()              _TIMER_EVENT(TMR_START, 0)
+#define SEQ_STOP_TIMER()               _TIMER_EVENT(TMR_STOP, 0)
+#define SEQ_CONTINUE_TIMER()           _TIMER_EVENT(TMR_CONTINUE, 0)
+#define SEQ_WAIT_TIME(ticks)           _TIMER_EVENT(TMR_WAIT_ABS, ticks)
+#define SEQ_DELTA_TIME(ticks)          _TIMER_EVENT(TMR_WAIT_REL, ticks)
+#define SEQ_ECHO_BACK(key)             _TIMER_EVENT(TMR_ECHO, key)
+#define SEQ_SET_TEMPO(value)           _TIMER_EVENT(TMR_TEMPO, value)
+#define SEQ_SONGPOS(pos)               _TIMER_EVENT(TMR_SPP, pos)
+#define SEQ_TIME_SIGNATURE(sig)                _TIMER_EVENT(TMR_TIMESIG, sig)
+
+/*
+ * Local control events
+ */
+
+#define _LOCAL_EVENT(ev, parm)         { \
+       _SEQ_NEEDBUF(8);\
+       _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
+       _seqbuf[_seqbufptr+1] = (ev); \
+       _seqbuf[_seqbufptr+2] = 0;\
+       _seqbuf[_seqbufptr+3] = 0;\
+       *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+       _SEQ_ADVBUF(8); \
+       }
+
+#define SEQ_PLAYAUDIO(devmask)         _LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
+/*
+ * Events for the level 1 interface only
+ */
+
+#define SEQ_MIDIOUT(device, byte)      { \
+       _SEQ_NEEDBUF(4);\
+       _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+       _seqbuf[_seqbufptr+1] = (byte);\
+       _seqbuf[_seqbufptr+2] = (device);\
+       _seqbuf[_seqbufptr+3] = 0;\
+       _SEQ_ADVBUF(4);}
+
+/*
+ * Patch loading.
+ */
+#define SEQ_WRPATCH(patchx, len)       { \
+       if (_seqbufptr) seqbuf_dump(); \
+       if (write(seqfd, (char*)(patchx), len)==-1) \
+          perror("Write patch: /dev/sequencer"); \
+       }
+
+#define SEQ_WRPATCH2(patchx, len)      \
+       ( seqbuf_dump(), write(seqfd, (char*)(patchx), len) )
+
+#endif
+
+/*
+ * Here I have moved all the aliases for ioctl names.
+ */
+
+#define SNDCTL_DSP_SAMPLESIZE  SNDCTL_DSP_SETFMT
+#define SOUND_PCM_WRITE_BITS   SNDCTL_DSP_SETFMT
+#define SOUND_PCM_SETFMT       SNDCTL_DSP_SETFMT
+
+#define SOUND_PCM_WRITE_RATE   SNDCTL_DSP_SPEED
+#define SOUND_PCM_POST         SNDCTL_DSP_POST
+#define SOUND_PCM_RESET                SNDCTL_DSP_RESET
+#define SOUND_PCM_SYNC         SNDCTL_DSP_SYNC
+#define SOUND_PCM_SUBDIVIDE    SNDCTL_DSP_SUBDIVIDE
+#define SOUND_PCM_SETFRAGMENT  SNDCTL_DSP_SETFRAGMENT
+#define SOUND_PCM_GETFMTS      SNDCTL_DSP_GETFMTS
+#define SOUND_PCM_GETOSPACE    SNDCTL_DSP_GETOSPACE
+#define SOUND_PCM_GETISPACE    SNDCTL_DSP_GETISPACE
+#define SOUND_PCM_NONBLOCK     SNDCTL_DSP_NONBLOCK
+#define SOUND_PCM_GETCAPS      SNDCTL_DSP_GETCAPS
+#define SOUND_PCM_GETTRIGGER   SNDCTL_DSP_GETTRIGGER
+#define SOUND_PCM_SETTRIGGER   SNDCTL_DSP_SETTRIGGER
+#define SOUND_PCM_SETSYNCRO    SNDCTL_DSP_SETSYNCRO
+#define SOUND_PCM_GETIPTR      SNDCTL_DSP_GETIPTR
+#define SOUND_PCM_GETOPTR      SNDCTL_DSP_GETOPTR
+#define SOUND_PCM_MAPINBUF     SNDCTL_DSP_MAPINBUF
+#define SOUND_PCM_MAPOUTBUF    SNDCTL_DSP_MAPOUTBUF
+
+/***********************************************************************/
+
+/**
+ * XXX OSSv4 defines -- some bits taken straight out of the new
+ * sys/soundcard.h bundled with recent OSS releases.
+ *
+ * NB:  These macros and structures will be reorganized and inserted
+ *     in appropriate places throughout this file once the code begins
+ *     to take shape.
+ *
+ * @todo reorganize layout more like the 4Front version
+ * @todo ask about maintaining __SIOWR vs. _IOWR ioctl cmd defines
+ */
+
+/**
+ * @note The @c OSSV4_EXPERIMENT macro is meant to wrap new development code
+ * in the sound system relevant to adopting 4Front's OSSv4 specification.
+ * Users should not enable this!  Really!
+ */
+#if 0
+# define OSSV4_EXPERIMENT 1
+#else
+# undef OSSV4_EXPERIMENT
+#endif
+
+#ifdef SOUND_VERSION
+# undef SOUND_VERSION
+# define SOUND_VERSION 0x040000
+#endif /* !SOUND_VERSION */
+
+#define OSS_LONGNAME_SIZE      64
+#define OSS_LABEL_SIZE         16
+#define OSS_DEVNODE_SIZE        32
+typedef char oss_longname_t[OSS_LONGNAME_SIZE];
+typedef char oss_label_t[OSS_LABEL_SIZE];
+typedef char oss_devnode_t[OSS_DEVNODE_SIZE];
+
+typedef struct audio_errinfo
+{
+       int             play_underruns;
+       int             rec_overruns;
+       unsigned int    play_ptradjust;
+       unsigned int    rec_ptradjust;
+       int             play_errorcount;
+       int             rec_errorcount;
+       int             play_lasterror;
+       int             rec_lasterror;
+       long            play_errorparm;
+       long            rec_errorparm;
+       int             filler[16];
+} audio_errinfo;
+
+#define SNDCTL_DSP_GETPLAYVOL           _IOR ('P', 24, int)
+#define SNDCTL_DSP_SETPLAYVOL           _IOWR('P', 24, int)
+#define SNDCTL_DSP_GETERROR             _IOR ('P', 25, audio_errinfo)
+
+
+/*
+ ****************************************************************************
+ * Sync groups for audio devices
+ */
+typedef struct oss_syncgroup
+{
+  int id;
+  int mode;
+  int filler[16];
+} oss_syncgroup;
+
+#define SNDCTL_DSP_SYNCGROUP            _IOWR('P', 28, oss_syncgroup)
+#define SNDCTL_DSP_SYNCSTART            _IOW ('P', 29, int)
+
+/*
+ **************************************************************************
+ * "cooked" mode enables software based conversions for sample rate, sample
+ * format (bits) and number of channels (mono/stereo). These conversions are
+ * required with some devices that support only one sample rate or just stereo
+ * to let the applications to use other formats. The cooked mode is enabled by
+ * default. However it's necessary to disable this mode when mmap() is used or
+ * when very deterministic timing is required. SNDCTL_DSP_COOKEDMODE is an
+ * optional call introduced in OSS 3.9.6f. It's _error return must be ignored_
+ * since normally this call will return erno=EINVAL.
+ *
+ * SNDCTL_DSP_COOKEDMODE must be called immediately after open before doing
+ * anything else. Otherwise the call will not have any effect.
+ */
+#define SNDCTL_DSP_COOKEDMODE           _IOW ('P', 30, int)
+
+/*
+ **************************************************************************
+ * SNDCTL_DSP_SILENCE and SNDCTL_DSP_SKIP are new calls in OSS 3.99.0
+ * that can be used to implement pause/continue during playback (no effect
+ * on recording).
+ */
+#define SNDCTL_DSP_SILENCE              _IO  ('P', 31)
+#define SNDCTL_DSP_SKIP                 _IO  ('P', 32)
+
+/*
+ ****************************************************************************
+ * Abort transfer (reset) functions for input and output
+ */
+#define SNDCTL_DSP_HALT_INPUT          _IO  ('P', 33)
+#define SNDCTL_DSP_RESET_INPUT SNDCTL_DSP_HALT_INPUT   /* Old name */
+#define SNDCTL_DSP_HALT_OUTPUT         _IO  ('P', 34)
+#define SNDCTL_DSP_RESET_OUTPUT        SNDCTL_DSP_HALT_OUTPUT  /* Old name */
+
+/*
+ ****************************************************************************
+ * Low water level control
+ */
+#define SNDCTL_DSP_LOW_WATER           _IOW ('P', 34, int)
+
+/** @todo Get rid of OSS_NO_LONG_LONG references? */
+
+/*
+ ****************************************************************************
+ * 64 bit pointer support. Only available in environments that support
+ * the 64 bit (long long) integer type.
+ */
+#ifndef OSS_NO_LONG_LONG
+typedef struct
+{
+  long long samples;
+  int fifo_samples;
+  int filler[32];              /* For future use */
+} oss_count_t;
+
+#define SNDCTL_DSP_CURRENT_IPTR                _IOR ('P', 35, oss_count_t)
+#define SNDCTL_DSP_CURRENT_OPTR                _IOR ('P', 36, oss_count_t)
+#endif
+
+/*
+ ****************************************************************************
+ * Interface for selecting recording sources and playback output routings.
+ */
+#define SNDCTL_DSP_GET_RECSRC_NAMES     _IOR ('P', 37, oss_mixer_enuminfo)
+#define SNDCTL_DSP_GET_RECSRC           _IOR ('P', 38, int)
+#define SNDCTL_DSP_SET_RECSRC           _IOWR('P', 38, int)
+
+#define SNDCTL_DSP_GET_PLAYTGT_NAMES    _IOR ('P', 39, oss_mixer_enuminfo)
+#define SNDCTL_DSP_GET_PLAYTGT          _IOR ('P', 40, int)
+#define SNDCTL_DSP_SET_PLAYTGT          _IOWR('P', 40, int)
+#define SNDCTL_DSP_GETRECVOL            _IOR ('P', 41, int)
+#define SNDCTL_DSP_SETRECVOL            _IOWR('P', 41, int)
+
+/*
+ ***************************************************************************
+ * Some calls for setting the channel assignment with multi channel devices
+ * (see the manual for details).                                                 */
+#define SNDCTL_DSP_GET_CHNORDER         _IOR ('P', 42, unsigned long long)
+#define SNDCTL_DSP_SET_CHNORDER         _IOWR('P', 42, unsigned long long)
+#       define CHID_UNDEF       0
+#       define CHID_L           1                                               #       define CHID_R           2
+#       define CHID_C           3
+#       define CHID_LFE         4
+#       define CHID_LS          5
+#       define CHID_RS          6
+#       define CHID_LR          7
+#       define CHID_RR          8
+#define CHNORDER_UNDEF          0x0000000000000000ULL
+#define CHNORDER_NORMAL         0x0000000087654321ULL
+
+#define MAX_PEAK_CHANNELS      128
+typedef unsigned short oss_peaks_t[MAX_PEAK_CHANNELS];
+#define SNDCTL_DSP_GETIPEAKS           _IOR('P', 43, oss_peaks_t)
+#define SNDCTL_DSP_GETOPEAKS           _IOR('P', 44, oss_peaks_t)
+#define SNDCTL_DSP_POLICY               _IOW('P', 45, int)    /* See the manual */
+
+/*
+ * OSS_SYSIFO is obsolete. Use SNDCTL_SYSINFO insteads.
+ */
+#define OSS_GETVERSION                  _IOR ('M', 118, int)
+
+/**
+ * @brief      Argument for SNDCTL_SYSINFO ioctl.
+ *
+ * For use w/ the SNDCTL_SYSINFO ioctl available on audio (/dev/dsp*),
+ * mixer, and MIDI devices.
+ */
+typedef struct oss_sysinfo
+{
+       char    product[32];    /* For example OSS/Free, OSS/Linux or
+                                  OSS/Solaris */
+       char    version[32];    /* For example 4.0a */
+       int     versionnum;     /* See OSS_GETVERSION */
+       char    options[128];   /* Reserved */
+
+       int     numaudios;      /* # of audio/dsp devices */
+       int     openedaudio[8]; /* Bit mask telling which audio devices
+                                  are busy */
+
+       int     numsynths;      /* # of availavle synth devices */
+       int     nummidis;       /* # of available MIDI ports */
+       int     numtimers;      /* # of available timer devices */
+       int     nummixers;      /* # of mixer devices */
+
+       int     openedmidi[8];  /* Bit mask telling which midi devices
+                                  are busy */
+       int     numcards;       /* Number of sound cards in the system */
+       int     filler[241];    /* For future expansion (set to -1) */
+} oss_sysinfo;
+
+typedef struct oss_mixext
+{
+  int dev;                     /* Mixer device number */
+  int ctrl;                    /* Controller number */
+  int type;                    /* Entry type */
+#      define MIXT_DEVROOT      0      /* Device root entry */
+#      define MIXT_GROUP        1      /* Controller group */
+#      define MIXT_ONOFF        2      /* OFF (0) or ON (1) */
+#      define MIXT_ENUM         3      /* Enumerated (0 to maxvalue) */
+#      define MIXT_MONOSLIDER   4      /* Mono slider (0 to 100) */
+#      define MIXT_STEREOSLIDER 5      /* Stereo slider (dual 0 to 100) */
+#      define MIXT_MESSAGE      6      /* (Readable) textual message */
+#      define MIXT_MONOVU       7      /* VU meter value (mono) */
+#      define MIXT_STEREOVU     8      /* VU meter value (stereo) */
+#      define MIXT_MONOPEAK     9      /* VU meter peak value (mono) */
+#      define MIXT_STEREOPEAK  10      /* VU meter peak value (stereo) */
+#      define MIXT_RADIOGROUP  11      /* Radio button group */
+#      define MIXT_MARKER      12      /* Separator between normal and extension entries */
+#      define MIXT_VALUE       13      /* Decimal value entry */
+#      define MIXT_HEXVALUE    14      /* Hexadecimal value entry */
+#      define MIXT_MONODB      15      /* Mono atten. slider (0 to -144) */
+#      define MIXT_STEREODB    16      /* Stereo atten. slider (dual 0 to -144) */
+#      define MIXT_SLIDER      17      /* Slider (mono) with full integer range */
+#      define MIXT_3D          18
+
+  /* Possible value range (minvalue to maxvalue) */
+  /* Note that maxvalue may also be smaller than minvalue */
+  int maxvalue;
+  int minvalue;
+
+  int flags;
+#      define MIXF_READABLE    0x00000001      /* Has readable value */
+#      define MIXF_WRITEABLE   0x00000002      /* Has writeable value */
+#      define MIXF_POLL        0x00000004      /* May change itself */
+#      define MIXF_HZ          0x00000008      /* Herz scale */
+#      define MIXF_STRING      0x00000010      /* Use dynamic extensions for value */
+#      define MIXF_DYNAMIC     0x00000010      /* Supports dynamic extensions */
+#      define MIXF_OKFAIL      0x00000020      /* Interpret value as 1=OK, 0=FAIL */
+#      define MIXF_FLAT        0x00000040      /* Flat vertical space requirements */
+#      define MIXF_LEGACY      0x00000080      /* Legacy mixer control group */
+  char id[16];                 /* Mnemonic ID (mainly for internal use) */
+  int parent;                  /* Entry# of parent (group) node (-1 if root) */
+
+  int dummy;                   /* Internal use */
+
+  int timestamp;
+
+  char data[64];               /* Misc data (entry type dependent) */
+  unsigned char enum_present[32];      /* Mask of allowed enum values */
+  int control_no;              /* SOUND_MIXER_VOLUME..SOUND_MIXER_MIDI */
+  /* (-1 means not indicated) */
+
+/*
+ * The desc field is reserved for internal purposes of OSS. It should not be 
+ * used by applications.
+ */
+  unsigned int desc;
+#define MIXEXT_SCOPE_MASK                      0x0000003f
+#define MIXEXT_SCOPE_OTHER                     0x00000000
+#define MIXEXT_SCOPE_INPUT                     0x00000001
+#define MIXEXT_SCOPE_OUTPUT                    0x00000002
+#define MIXEXT_SCOPE_MONITOR                   0x00000003
+#define MIXEXT_SCOPE_RECSWITCH                 0x00000004
+
+  char extname[32];
+  int update_counter;
+  int filler[7];
+} oss_mixext;
+
+typedef struct oss_mixext_root
+{
+  char id[16];
+  char name[48];
+} oss_mixext_root;
+
+typedef struct oss_mixer_value
+{
+  int dev;
+  int ctrl;
+  int value;
+  int flags;                   /* Reserved for future use. Initialize to 0 */
+  int timestamp;               /* Must be set to oss_mixext.timestamp */
+  int filler[8];               /* Reserved for future use. Initialize to 0 */
+} oss_mixer_value;
+
+#define OSS_ENUM_MAXVALUE       255
+typedef struct oss_mixer_enuminfo
+{
+       int     dev;
+       int     ctrl;
+       int     nvalues;
+       int     version;                  /* Read the manual */
+       short   strindex[OSS_ENUM_MAXVALUE];
+       char    strings[3000];
+} oss_mixer_enuminfo;
+
+#define OPEN_READ       PCM_ENABLE_INPUT
+#define OPEN_WRITE      PCM_ENABLE_OUTPUT
+#define OPEN_READWRITE  (OPEN_READ|OPEN_WRITE)
+
+/**
+ * @brief      Argument for SNDCTL_AUDIOINFO ioctl.
+ *
+ * For use w/ the SNDCTL_AUDIOINFO ioctl available on audio (/dev/dsp*)
+ * devices.
+ */
+typedef struct oss_audioinfo
+{
+       int     dev;            /* Audio device number */
+       char    name[64];
+       int     busy;           /* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */
+       int     pid;
+       int     caps;           /* DSP_CAP_INPUT, DSP_CAP_OUTPUT */
+       int     iformats;
+       int     oformats;
+       int     magic;          /* Reserved for internal use */
+       char    cmd[64];        /* Command using the device (if known) */
+       int     card_number;
+       int     port_number;
+       int     mixer_dev;
+       int     real_device;    /* Obsolete field. Replaced by devnode */
+       int     enabled;        /* 1=enabled, 0=device not ready at this
+                                  moment */
+       int     flags;          /* For internal use only - no practical
+                                  meaning */
+       int     min_rate;       /* Sample rate limits */
+       int     max_rate;
+       int     min_channels;   /* Number of channels supported */
+       int     max_channels;
+       int     binding;        /* DSP_BIND_FRONT, etc. 0 means undefined */
+       int     rate_source;
+       char    handle[32];
+       #define OSS_MAX_SAMPLE_RATES    20      /* Cannot be changed  */
+       unsigned int nrates;
+       unsigned int rates[OSS_MAX_SAMPLE_RATES]; /* Please read the manual before using these */
+       oss_longname_t  song_name;      /* Song name (if given) */
+       oss_label_t     label;          /* Device label (if given) */
+       int             latency;        /* In usecs, -1=unknown */
+       oss_devnode_t   devnode;        /* Device special file name (inside
+                                          /dev) */
+       int filler[186];
+} oss_audioinfo;
+
+typedef struct oss_mixerinfo
+{
+  int dev;
+  char id[16];
+  char name[32];
+  int modify_counter;
+  int card_number;
+  int port_number;
+  char handle[32];
+  int magic;                   /* Reserved */
+  int enabled;                 /* Reserved */
+  int caps;
+#define MIXER_CAP_VIRTUAL                              0x00000001
+  int flags;                   /* Reserved */
+  int nrext;
+  /*
+   * The priority field can be used to select the default (motherboard)
+   * mixer device. The mixer with the highest priority is the
+   * most preferred one. -2 or less means that this device cannot be used
+   * as the default mixer.
+   */
+  int priority;
+  int filler[254];             /* Reserved */
+} oss_mixerinfo;
+
+typedef struct oss_midi_info
+{
+  int dev;                     /* Midi device number */
+  char name[64];
+  int busy;                    /* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */
+  int pid;
+  char cmd[64];                        /* Command using the device (if known) */
+  int caps;
+#define MIDI_CAP_MPU401                0x00000001      /**** OBSOLETE ****/
+#define MIDI_CAP_INPUT         0x00000002
+#define MIDI_CAP_OUTPUT                0x00000004
+#define MIDI_CAP_INOUT         (MIDI_CAP_INPUT|MIDI_CAP_OUTPUT)
+#define MIDI_CAP_VIRTUAL       0x00000008      /* Pseudo device */
+#define MIDI_CAP_MTCINPUT      0x00000010      /* Supports SNDCTL_MIDI_MTCINPUT */
+#define MIDI_CAP_CLIENT                0x00000020      /* Virtual client side device */
+#define MIDI_CAP_SERVER                0x00000040      /* Virtual server side device */
+#define MIDI_CAP_INTERNAL      0x00000080      /* Internal (synth) device */
+#define MIDI_CAP_EXTERNAL      0x00000100      /* external (MIDI port) device */
+#define MIDI_CAP_PTOP          0x00000200      /* Point to point link to one device */
+#define MIDI_CAP_MTC           0x00000400      /* MTC/SMPTE (control) device */
+  int magic;                   /* Reserved for internal use */
+  int card_number;
+  int port_number;
+  int enabled;                 /* 1=enabled, 0=device not ready at this moment */
+  int flags;                   /* For internal use only - no practical meaning */
+  char handle[32];
+  oss_longname_t song_name;    /* Song name (if known) */
+  oss_label_t label;           /* Device label (if given) */
+  int latency;                 /* In usecs, -1=unknown */
+  int filler[244];
+} oss_midi_info;
+
+typedef struct oss_card_info
+{
+  int card;
+  char shortname[16];
+  char longname[128];
+  int flags;
+  int filler[256];
+} oss_card_info;
+
+#define SNDCTL_SYSINFO          _IOR ('X', 1, oss_sysinfo)
+#define OSS_SYSINFO             SNDCTL_SYSINFO /* Old name */
+
+#define SNDCTL_MIX_NRMIX       _IOR ('X', 2, int)
+#define SNDCTL_MIX_NREXT       _IOWR('X', 3, int)
+#define SNDCTL_MIX_EXTINFO     _IOWR('X', 4, oss_mixext)
+#define SNDCTL_MIX_READ                _IOWR('X', 5, oss_mixer_value)
+#define SNDCTL_MIX_WRITE       _IOWR('X', 6, oss_mixer_value)
+
+#define SNDCTL_AUDIOINFO       _IOWR('X', 7, oss_audioinfo)
+#define SNDCTL_MIX_ENUMINFO    _IOWR('X', 8, oss_mixer_enuminfo)
+#define SNDCTL_MIDIINFO                _IOWR('X', 9, oss_midi_info)
+#define SNDCTL_MIXERINFO       _IOWR('X',10, oss_mixerinfo)
+#define SNDCTL_CARDINFO                _IOWR('X',11, oss_card_info)
+
+/*
+ * Few more "globally" available ioctl calls.
+ */
+#define SNDCTL_SETSONG          _IOW ('Y', 2, oss_longname_t)
+#define SNDCTL_GETSONG          _IOR ('Y', 2, oss_longname_t)
+#define SNDCTL_SETNAME          _IOW ('Y', 3, oss_longname_t)
+#define SNDCTL_SETLABEL         _IOW ('Y', 4, oss_label_t)
+#define SNDCTL_GETLABEL         _IOR ('Y', 4, oss_label_t)
+
+#endif /* !_SYS_SOUNDCARD_H_ */
diff --git a/src/deps/rtaudio-mod/librtaudio.pc b/src/deps/rtaudio-mod/librtaudio.pc
new file mode 100644 (file)
index 0000000..3adc679
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include        
+
+Name: librtaudio
+Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output
+Version: 4.1.1
+Requires:  alsa libpulse-simple 
+Libs: -L${libdir} -lrtaudio
+Libs.private: -lpthread
+Cflags: -pthread -I${includedir}   -DHAVE_GETTIMEOFDAY  -D__UNIX_JACK__ -D__LINUX_ALSA__ -D__LINUX_PULSE__
diff --git a/src/deps/rtaudio-mod/librtaudio.pc.in b/src/deps/rtaudio-mod/librtaudio.pc.in
new file mode 100644 (file)
index 0000000..45c3f4e
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include        
+
+Name: librtaudio
+Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output
+Version: 4.1.1
+Requires: @req@ 
+Libs: -L${libdir} -lrtaudio
+Libs.private: -lpthread
+Cflags: -pthread -I${includedir} @CPPFLAGS@
\ No newline at end of file
diff --git a/src/deps/rtaudio-mod/rtaudio-config b/src/deps/rtaudio-mod/rtaudio-config
new file mode 100755 (executable)
index 0000000..dbd3a39
--- /dev/null
@@ -0,0 +1,19 @@
+#! /bin/sh
+if (test "x$#" != "x1") ; then
+  echo "Usage: $0 [--libs | --cxxflags | --cppflags]"
+  exit;
+fi
+
+LIBRARY="-lpthread -lasound -lasound -ljack  -lpulse-simple -lpulse "
+CXXFLAGS="-O2 -Wall -Wextra"
+CPPFLAGS="  -DHAVE_GETTIMEOFDAY  -D__UNIX_JACK__ -D__LINUX_ALSA__ -D__LINUX_PULSE__"
+
+if (test "x$1" = "x--libs") ; then
+  echo "$LIBRARY -lrtaudio"
+elif (test "x$1" = "x--cxxflags") ; then
+  echo "$CXXFLAGS"
+elif (test "x$1" = "x--cppflags") ; then
+  echo "$CPPFLAGS"
+else
+  echo "Unknown option: $1"
+fi
diff --git a/src/deps/rtaudio-mod/rtaudio-config.in b/src/deps/rtaudio-mod/rtaudio-config.in
new file mode 100644 (file)
index 0000000..5f83d51
--- /dev/null
@@ -0,0 +1,19 @@
+#! /bin/sh
+if (test "x$#" != "x1") ; then
+  echo "Usage: $0 [--libs | --cxxflags | --cppflags]"
+  exit;
+fi
+
+LIBRARY="@LIBS@"
+CXXFLAGS="@CXXFLAGS@"
+CPPFLAGS="@CPPFLAGS@"
+
+if (test "x$1" = "x--libs") ; then
+  echo "$LIBRARY -lrtaudio"
+elif (test "x$1" = "x--cxxflags") ; then
+  echo "$CXXFLAGS"
+elif (test "x$1" = "x--cppflags") ; then
+  echo "$CPPFLAGS"
+else
+  echo "Unknown option: $1"
+fi
diff --git a/src/deps/rtaudio-mod/tests/Makefile.in b/src/deps/rtaudio-mod/tests/Makefile.in
new file mode 100644 (file)
index 0000000..fbca16b
--- /dev/null
@@ -0,0 +1,58 @@
+### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in
+### RtAudio tests Makefile - for various flavors of unix and MinGW
+
+PROGRAMS = audioprobe playsaw playraw record duplex testall teststops
+RM = /bin/rm
+SRC_PATH = ..
+INCLUDE = ..
+OBJECT_PATH = @object_path@
+vpath %.o $(OBJECT_PATH)
+
+OBJECTS        =       RtAudio.o @objects@
+
+CC       = @CXX@
+DEFS     = @CPPFLAGS@
+CFLAGS   = @CXXFLAGS@
+CFLAGS  += -I$(INCLUDE) -I../include
+LIBRARY  = @LIBS@
+
+%.o : $(SRC_PATH)/%.cpp
+       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
+
+%.o : ../include/%.cpp
+       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
+
+all : $(PROGRAMS)
+
+audioprobe : audioprobe.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o audioprobe audioprobe.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+playsaw : playsaw.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o playsaw playsaw.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+playraw : playraw.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o playraw playraw.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+record : record.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o record record.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+duplex : duplex.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o duplex duplex.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+testall : testall.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o testall testall.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+teststops : teststops.cpp $(OBJECTS)
+       $(CC) $(CFLAGS) $(DEFS) -o teststops teststops.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
+
+clean : 
+       $(RM) -f $(OBJECT_PATH)/*.o
+       $(RM) -f $(PROGRAMS)
+       $(RM) -f *.raw *~ *.exe
+       $(RM) -fR *.dSYM
+
+distclean: clean
+       $(RM) -f Makefile
+
+strip : 
+       strip $(PROGRAMS)
diff --git a/src/deps/vst/aeffect.h b/src/deps/vst/aeffect.h
new file mode 100644 (file)
index 0000000..f5f01c8
--- /dev/null
@@ -0,0 +1,351 @@
+//-------------------------------------------------------------------------------------------------------\r
+// VST Plug-Ins SDK\r
+// Version 2.4         $Date: 2006/06/20 17:22:55 $\r
+//\r
+// Category     : VST 2.x Interfaces\r
+// Filename     : aeffect.h\r
+// Created by   : Steinberg Media Technologies\r
+// Description  : Definition of AEffect structure\r
+//\r
+// © 2006, Steinberg Media Technologies, All Rights Reserved\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __aeffect__\r
+#define __aeffect__\r
+\r
+// gcc based compiler, or CodeWarrior on Mac OS X\r
+#if ((defined(__GNUC__) && (defined(__APPLE_CPP__) || defined(__APPLE_CC__))) || (defined (__MWERKS__) && defined (__MACH__)))\r
+       #ifndef TARGET_API_MAC_CARBON\r
+               #define TARGET_API_MAC_CARBON 1\r
+       #endif\r
+       #if __ppc__\r
+               #ifndef VST_FORCE_DEPRECATED\r
+                       #define VST_FORCE_DEPRECATED 0\r
+               #endif\r
+       #endif\r
+#endif\r
+\r
+#if TARGET_API_MAC_CARBON\r
+       #ifdef __LP64__\r
+               #pragma options align=power\r
+       #else\r
+               #pragma options align=mac68k\r
+       #endif\r
+       #define VSTCALLBACK\r
+#elif defined __BORLANDC__\r
+       #pragma -a8\r
+#elif defined(__GNUC__)\r
+    #pragma pack(push,8)\r
+    #define VSTCALLBACK __cdecl\r
+#elif defined(WIN32) || defined(__FLAT__) || defined CBUILDER\r
+       #pragma pack(push)\r
+       #pragma pack(8)\r
+       #define VSTCALLBACK __cdecl\r
+#else\r
+       #define VSTCALLBACK\r
+#endif\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#include <string.h>    // for strncpy\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// VST Version\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+/** Define SDK Version (you can generate different versions (from 2.0 to 2.4) of this SDK by setting the unwanted extensions to 0). */\r
+#define VST_2_1_EXTENSIONS 1 ///< Version 2.1 extensions (08-06-2000)\r
+#define VST_2_2_EXTENSIONS 1 ///< Version 2.2 extensions (08-06-2001)\r
+#define VST_2_3_EXTENSIONS 1 ///< Version 2.3 extensions (20-05-2003)\r
+#ifndef VST_2_4_EXTENSIONS\r
+#define VST_2_4_EXTENSIONS 1 ///< Version 2.4 extensions (01-01-2006)\r
+#endif\r
+\r
+/** Current VST Version */\r
+#if VST_2_4_EXTENSIONS\r
+       #define kVstVersion 2400\r
+#elif VST_2_3_EXTENSIONS\r
+       #define kVstVersion 2300\r
+#elif VST_2_2_EXTENSIONS\r
+       #define kVstVersion 2200\r
+#elif VST_2_1_EXTENSIONS\r
+       #define kVstVersion 2100\r
+#else\r
+       #define kVstVersion 2\r
+#endif\r
+\r
+/** Disable for Hosts to serve Plug-ins below VST 2.4 */\r
+#ifndef VST_FORCE_DEPRECATED\r
+#define VST_FORCE_DEPRECATED VST_2_4_EXTENSIONS \r
+#endif\r
+\r
+/** Declares identifier as deprecated. */\r
+#if VST_FORCE_DEPRECATED\r
+#define DECLARE_VST_DEPRECATED(identifier) __##identifier##Deprecated\r
+#else\r
+#define DECLARE_VST_DEPRECATED(identifier) identifier\r
+#endif\r
+\r
+/** Define for 64 Bit Platform. */\r
+#ifndef VST_64BIT_PLATFORM\r
+#define VST_64BIT_PLATFORM _WIN64 || __LP64__\r
+#endif\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Integral Types\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#ifdef WIN32\r
+typedef short VstInt16;                                ///< 16 bit integer type\r
+typedef int VstInt32;                          ///< 32 bit integer type\r
+typedef __int64 VstInt64;                      ///< 64 bit integer type\r
+#else\r
+#include <stdint.h>\r
+typedef int16_t VstInt16;                      ///< 16 bit integer type\r
+typedef int32_t VstInt32;                      ///< 32 bit integer type\r
+typedef int64_t VstInt64;                      ///< 64 bit integer type\r
+#endif\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Generic Types\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#if VST_64BIT_PLATFORM\r
+typedef VstInt64 VstIntPtr;                    ///< platform-dependent integer type, same size as pointer\r
+#else\r
+typedef VstInt32 VstIntPtr;                    ///< platform-dependent integer type, same size as pointer\r
+#endif\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Misc. Definition\r
+//-------------------------------------------------------------------------------------------------------\r
+#undef CCONST\r
+struct AEffect;\r
+\r
+/// @cond ignore\r
+typedef        VstIntPtr (VSTCALLBACK *audioMasterCallback) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);\r
+typedef VstIntPtr (VSTCALLBACK *AEffectDispatcherProc) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);\r
+typedef void (VSTCALLBACK *AEffectProcessProc) (AEffect* effect, float** inputs, float** outputs, VstInt32 sampleFrames);\r
+typedef void (VSTCALLBACK *AEffectProcessDoubleProc) (AEffect* effect, double** inputs, double** outputs, VstInt32 sampleFrames);\r
+typedef void (VSTCALLBACK *AEffectSetParameterProc) (AEffect* effect, VstInt32 index, float parameter);\r
+typedef float (VSTCALLBACK *AEffectGetParameterProc) (AEffect* effect, VstInt32 index);\r
+/// @endcond\r
+\r
+/** Four Character Constant (for AEffect->uniqueID) */\r
+#define CCONST(a, b, c, d) \\r
+        ((((VstInt32)a) << 24) | (((VstInt32)b) << 16) | (((VstInt32)c) << 8) | (((VstInt32)d) << 0))\r
+\r
+/** AEffect magic number */\r
+#define kEffectMagic CCONST ('V', 's', 't', 'P')\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Basic VST Effect "C" Interface. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct AEffect\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 magic;                 ///< must be #kEffectMagic ('VstP')\r
+\r
+       /** Host to Plug-in dispatcher @see AudioEffect::dispatcher */\r
+       AEffectDispatcherProc dispatcher;\r
+       \r
+       /** \deprecated Accumulating process mode is deprecated in VST 2.4! Use AEffect::processReplacing instead! */\r
+       AEffectProcessProc DECLARE_VST_DEPRECATED (process);\r
+       \r
+       /** Set new value of automatable parameter @see AudioEffect::setParameter */\r
+       AEffectSetParameterProc setParameter;\r
+\r
+       /** Returns current value of automatable parameter @see AudioEffect::getParameter*/\r
+       AEffectGetParameterProc getParameter;\r
+\r
+       VstInt32 numPrograms;   ///< number of programs\r
+       VstInt32 numParams;             ///< all programs are assumed to have numParams parameters\r
+       VstInt32 numInputs;             ///< number of audio inputs\r
+       VstInt32 numOutputs;    ///< number of audio outputs\r
+\r
+       VstInt32 flags;                 ///< @see VstAEffectFlags\r
+       \r
+       VstIntPtr resvd1;               ///< reserved for Host, must be 0\r
+       VstIntPtr resvd2;               ///< reserved for Host, must be 0\r
+       \r
+       VstInt32 initialDelay;  ///< for algorithms which need input in the first place (Group delay or latency in Samples). This value should be initialized in a resume state.\r
+       \r
+       VstInt32 DECLARE_VST_DEPRECATED (realQualities);        ///< \deprecated unused member\r
+       VstInt32 DECLARE_VST_DEPRECATED (offQualities);         ///< \deprecated unused member\r
+       float    DECLARE_VST_DEPRECATED (ioRatio);                      ///< \deprecated unused member\r
+\r
+       void* object;                   ///< #AudioEffect class pointer\r
+       void* user;                             ///< user-defined pointer\r
+\r
+       VstInt32 uniqueID;              ///< registered unique identifier (register it at Steinberg 3rd party support Web). This is used to identify a plug-in during save+load of preset and project.\r
+       VstInt32 version;               ///< plug-in version (example 1100 for version 1.1.0.0)\r
+\r
+       /** Process audio samples in replacing mode @see AudioEffect::processReplacing */\r
+       AEffectProcessProc processReplacing;\r
+\r
+#if VST_2_4_EXTENSIONS\r
+       /** Process double-precision audio samples in replacing mode @see AudioEffect::processDoubleReplacing */\r
+       AEffectProcessDoubleProc processDoubleReplacing;\r
+       \r
+       char future[56];                ///< reserved for future use (please zero)\r
+#else\r
+       char future[60];                ///< reserved for future use (please zero)\r
+#endif\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** AEffect flags */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstAEffectFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       effFlagsHasEditor     = 1 << 0,                 ///< set if the plug-in provides a custom editor\r
+       effFlagsCanReplacing  = 1 << 4,                 ///< supports replacing process mode (which should the default mode in VST 2.4)\r
+       effFlagsProgramChunks = 1 << 5,                 ///< program data is handled in formatless chunks\r
+       effFlagsIsSynth       = 1 << 8,                 ///< plug-in is a synth (VSTi), Host may assign mixer channels for its outputs\r
+       effFlagsNoSoundInStop = 1 << 9,                 ///< plug-in does not produce sound when input is all silence\r
+\r
+#if VST_2_4_EXTENSIONS\r
+       effFlagsCanDoubleReplacing = 1 << 12,   ///< plug-in supports double precision processing\r
+#endif\r
+\r
+       DECLARE_VST_DEPRECATED (effFlagsHasClip) = 1 << 1,                      ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effFlagsHasVu)   = 1 << 2,                      ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effFlagsCanMono) = 1 << 3,                      ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effFlagsExtIsAsync)   = 1 << 10,        ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effFlagsExtHasBuffer) = 1 << 11         ///< \deprecated deprecated in VST 2.4\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Basic dispatcher Opcodes (Host to Plug-in) */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum AEffectOpcodes\r
+{\r
+       effOpen = 0,            ///< no arguments  @see AudioEffect::open\r
+       effClose,                       ///< no arguments  @see AudioEffect::close\r
+\r
+       effSetProgram,          ///< [value]: new program number  @see AudioEffect::setProgram\r
+       effGetProgram,          ///< [return value]: current program number  @see AudioEffect::getProgram\r
+       effSetProgramName,      ///< [ptr]: char* with new program name, limited to #kVstMaxProgNameLen  @see AudioEffect::setProgramName\r
+       effGetProgramName,      ///< [ptr]: char buffer for current program name, limited to #kVstMaxProgNameLen  @see AudioEffect::getProgramName\r
+       \r
+       effGetParamLabel,       ///< [ptr]: char buffer for parameter label, limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterLabel\r
+       effGetParamDisplay,     ///< [ptr]: char buffer for parameter display, limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterDisplay\r
+       effGetParamName,        ///< [ptr]: char buffer for parameter name, limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterName\r
+       \r
+       DECLARE_VST_DEPRECATED (effGetVu),      ///< \deprecated deprecated in VST 2.4\r
+\r
+       effSetSampleRate,       ///< [opt]: new sample rate for audio processing  @see AudioEffect::setSampleRate\r
+       effSetBlockSize,        ///< [value]: new maximum block size for audio processing  @see AudioEffect::setBlockSize\r
+       effMainsChanged,        ///< [value]: 0 means "turn off", 1 means "turn on"  @see AudioEffect::suspend @see AudioEffect::resume\r
+\r
+       effEditGetRect,         ///< [ptr]: #ERect** receiving pointer to editor size  @see ERect @see AEffEditor::getRect\r
+       effEditOpen,            ///< [ptr]: system dependent Window pointer, e.g. HWND on Windows  @see AEffEditor::open\r
+       effEditClose,           ///< no arguments @see AEffEditor::close\r
+\r
+       DECLARE_VST_DEPRECATED (effEditDraw),   ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effEditMouse),  ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effEditKey),    ///< \deprecated deprecated in VST 2.4\r
+\r
+       effEditIdle,            ///< no arguments @see AEffEditor::idle\r
+       \r
+       DECLARE_VST_DEPRECATED (effEditTop),    ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effEditSleep),  ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (effIdentify),   ///< \deprecated deprecated in VST 2.4\r
+       \r
+       effGetChunk,            ///< [ptr]: void** for chunk data address [index]: 0 for bank, 1 for program  @see AudioEffect::getChunk\r
+       effSetChunk,            ///< [ptr]: chunk data [value]: byte size [index]: 0 for bank, 1 for program  @see AudioEffect::setChunk\r
\r
+       effNumOpcodes           \r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Basic dispatcher Opcodes (Plug-in to Host) */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum AudioMasterOpcodes\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       audioMasterAutomate = 0,        ///< [index]: parameter index [opt]: parameter value  @see AudioEffect::setParameterAutomated\r
+       audioMasterVersion,                     ///< [return value]: Host VST version (for example 2400 for VST 2.4) @see AudioEffect::getMasterVersion\r
+       audioMasterCurrentId,           ///< [return value]: current unique identifier on shell plug-in  @see AudioEffect::getCurrentUniqueId\r
+       audioMasterIdle,                        ///< no arguments  @see AudioEffect::masterIdle\r
+       DECLARE_VST_DEPRECATED (audioMasterPinConnected) ///< \deprecated deprecated in VST 2.4 r2\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** String length limits (in characters excl. 0 byte) */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstStringConstants\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstMaxProgNameLen   = 24,      ///< used for #effGetProgramName, #effSetProgramName, #effGetProgramNameIndexed\r
+       kVstMaxParamStrLen   = 8,       ///< used for #effGetParamLabel, #effGetParamDisplay, #effGetParamName\r
+       kVstMaxVendorStrLen  = 64,      ///< used for #effGetVendorString, #audioMasterGetVendorString\r
+       kVstMaxProductStrLen = 64,      ///< used for #effGetProductString, #audioMasterGetProductString\r
+       kVstMaxEffectNameLen = 32       ///< used for #effGetEffectName\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** String copy taking care of null terminator. */\r
+//-------------------------------------------------------------------------------------------------------\r
+inline char* vst_strncpy (char* dst, const char* src, size_t maxLen)\r
+{\r
+       char* result = strncpy (dst, src, maxLen);\r
+       dst[maxLen] = 0;\r
+       return result;\r
+}\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** String concatenation taking care of null terminator. */\r
+//-------------------------------------------------------------------------------------------------------\r
+inline char* vst_strncat (char* dst, const char* src, size_t maxLen)\r
+{\r
+       char* result = strncat (dst, src, maxLen);\r
+       dst[maxLen] = 0;\r
+       return result;\r
+}\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Cast #VstIntPtr to pointer. */\r
+//-------------------------------------------------------------------------------------------------------\r
+template <class T> inline T* FromVstPtr (VstIntPtr& arg)\r
+{\r
+       T** address = (T**)&arg;\r
+       return *address;\r
+}\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Cast pointer to #VstIntPtr. */\r
+//-------------------------------------------------------------------------------------------------------\r
+template <class T> inline VstIntPtr ToVstPtr (T* ptr)\r
+{\r
+       VstIntPtr* address = (VstIntPtr*)&ptr;\r
+       return *address;\r
+}\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Structure used for #effEditGetRect. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct ERect\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt16 top;           ///< top coordinate\r
+       VstInt16 left;          ///< left coordinate\r
+       VstInt16 bottom;        ///< bottom coordinate\r
+       VstInt16 right;         ///< right coordinate\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+#if TARGET_API_MAC_CARBON\r
+       #pragma options align=reset\r
+#elif defined(WIN32) || defined(__FLAT__) || defined(__GNUC__)\r
+       #pragma pack(pop)\r
+#elif defined __BORLANDC__\r
+       #pragma -a-\r
+#endif\r
+\r
+#endif // __aeffect__\r
diff --git a/src/deps/vst/aeffectx.h b/src/deps/vst/aeffectx.h
new file mode 100644 (file)
index 0000000..8bf7043
--- /dev/null
@@ -0,0 +1,1143 @@
+//-------------------------------------------------------------------------------------------------------\r
+// VST Plug-Ins SDK\r
+// Version 2.4         $Date: 2006/06/20 12:43:42 $\r
+//\r
+// Category     : VST 2.x Interfaces\r
+// Filename     : aeffectx.h\r
+// Created by   : Steinberg Media Technologies\r
+// Description  : Definition of auxiliary structures, extensions from VST 1.0 to VST 2.4\r
+//\r
+// © 2006, Steinberg Media Technologies, All Rights Reserved\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __aeffectx__\r
+#define __aeffectx__\r
+\r
+#ifndef __aeffect__\r
+#include "aeffect.h"\r
+#endif\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+#if TARGET_API_MAC_CARBON\r
+       #ifdef __LP64__\r
+       #pragma options align=power\r
+       #else\r
+       #pragma options align=mac68k\r
+       #endif\r
+#elif defined __BORLANDC__\r
+       #pragma -a8\r
+#elif defined(__GNUC__)\r
+    #pragma pack(push,8)\r
+#elif defined(WIN32) || defined(__FLAT__)\r
+       #pragma pack(push)\r
+       #pragma pack(8)\r
+#endif\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** String length limits (in characters excl. 0 byte). */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum Vst2StringConstants\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstMaxNameLen       = 64,      ///< used for #MidiProgramName, #MidiProgramCategory, #MidiKeyName, #VstSpeakerProperties, #VstPinProperties\r
+       kVstMaxLabelLen      = 64,      ///< used for #VstParameterProperties->label, #VstPinProperties->label\r
+       kVstMaxShortLabelLen = 8,       ///< used for #VstParameterProperties->shortLabel, #VstPinProperties->shortLabel\r
+       kVstMaxCategLabelLen = 24,      ///< used for #VstParameterProperties->label\r
+       kVstMaxFileNameLen   = 100      ///< used for #VstAudioFile->name\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+//-------------------------------------------------------------------------------------------------------\r
+// VstEvent\r
+//-------------------------------------------------------------------------------------------------------\r
+//-------------------------------------------------------------------------------------------------------\r
+/** A generic timestamped event. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstEvent\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 type;                  ///< @see VstEventTypes\r
+       VstInt32 byteSize;              ///< size of this event, excl. type and byteSize\r
+       VstInt32 deltaFrames;   ///< sample frames related to the current block start sample position\r
+       VstInt32 flags;                 ///< generic flags, none defined yet\r
+\r
+       char data[16];                  ///< data size may vary, depending on event type\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** VstEvent Types used by #VstEvent. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstEventTypes\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstMidiType = 1,               ///< MIDI event  @see VstMidiEvent\r
+       DECLARE_VST_DEPRECATED (kVstAudioType),         ///< \deprecated unused event type\r
+       DECLARE_VST_DEPRECATED (kVstVideoType),         ///< \deprecated unused event type\r
+       DECLARE_VST_DEPRECATED (kVstParameterType),     ///< \deprecated unused event type\r
+       DECLARE_VST_DEPRECATED (kVstTriggerType),       ///< \deprecated unused event type\r
+       kVstSysExType                   ///< MIDI system exclusive  @see VstMidiSysexEvent\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** A block of events for the current processed audio block. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstEvents\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 numEvents;             ///< number of Events in array\r
+       VstIntPtr reserved;             ///< zero (Reserved for future use)\r
+       VstEvent* events[2];    ///< event pointer array, variable size\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** MIDI Event (to be casted from VstEvent). */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstMidiEvent\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 type;                  ///< #kVstMidiType\r
+       VstInt32 byteSize;              ///< sizeof (VstMidiEvent)\r
+       VstInt32 deltaFrames;   ///< sample frames related to the current block start sample position\r
+       VstInt32 flags;                 ///< @see VstMidiEventFlags\r
+       VstInt32 noteLength;    ///< (in sample frames) of entire note, if available, else 0\r
+       VstInt32 noteOffset;    ///< offset (in sample frames) into note from note start if available, else 0\r
+       char midiData[4];               ///< 1 to 3 MIDI bytes; midiData[3] is reserved (zero)\r
+       char detune;                    ///< -64 to +63 cents; for scales other than 'well-tempered' ('microtuning')\r
+       char noteOffVelocity;   ///< Note Off Velocity [0, 127]\r
+       char reserved1;                 ///< zero (Reserved for future use)\r
+       char reserved2;                 ///< zero (Reserved for future use)\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstMidiEvent. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstMidiEventFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstMidiEventIsRealtime = 1 << 0        ///< means that this event is played life (not in playback from a sequencer track).\n This allows the Plug-In to handle these flagged events with higher priority, especially when the Plug-In has a big latency (AEffect::initialDelay)\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** MIDI Sysex Event (to be casted from #VstEvent). */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstMidiSysexEvent\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 type;                  ///< #kVstSysexType\r
+       VstInt32 byteSize;              ///< sizeof (VstMidiSysexEvent)\r
+       VstInt32 deltaFrames;   ///< sample frames related to the current block start sample position\r
+       VstInt32 flags;                 ///< none defined yet (should be zero)\r
+       VstInt32 dumpBytes;             ///< byte size of sysexDump\r
+       VstIntPtr resvd1;               ///< zero (Reserved for future use)\r
+       char* sysexDump;                ///< sysex dump\r
+       VstIntPtr resvd2;               ///< zero (Reserved for future use)\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// VstTimeInfo\r
+//-------------------------------------------------------------------------------------------------------\r
+//-------------------------------------------------------------------------------------------------------\r
+/** VstTimeInfo requested via #audioMasterGetTime.  @see AudioEffectX::getTimeInfo \r
+\r
+\note VstTimeInfo::samplePos :Current Position. It must always be valid, and should not cost a lot to ask for. The sample position is ahead of the time displayed to the user. In sequencer stop mode, its value does not change. A 32 bit integer is too small for sample positions, and it's a double to make it easier to convert between ppq and samples.\r
+\note VstTimeInfo::ppqPos : At tempo 120, 1 quarter makes 1/2 second, so 2.0 ppq translates to 48000 samples at 48kHz sample rate.\r
+.25 ppq is one sixteenth note then. if you need something like 480ppq, you simply multiply ppq by that scaler.\r
+\note VstTimeInfo::barStartPos : Say we're at bars/beats readout 3.3.3. That's 2 bars + 2 q + 2 sixteenth, makes 2 * 4 + 2 + .25 = 10.25 ppq. at tempo 120, that's 10.25 * .5 = 5.125 seconds, times 48000 = 246000 samples (if my calculator servers me well :-). \r
+\note VstTimeInfo::samplesToNextClock : MIDI Clock Resolution (24 per Quarter Note), can be negative the distance to the next midi clock (24 ppq, pulses per quarter) in samples. unless samplePos falls precicely on a midi clock, this will either be negative such that the previous MIDI clock is addressed, or positive when referencing the following (future) MIDI clock.\r
+*/\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstTimeInfo\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       double samplePos;                               ///< current Position in audio samples (always valid)\r
+       double sampleRate;                              ///< current Sample Rate in Herz (always valid)\r
+       double nanoSeconds;                             ///< System Time in nanoseconds (10^-9 second)\r
+       double ppqPos;                                  ///< Musical Position, in Quarter Note (1.0 equals 1 Quarter Note)\r
+       double tempo;                                   ///< current Tempo in BPM (Beats Per Minute)\r
+       double barStartPos;                             ///< last Bar Start Position, in Quarter Note\r
+       double cycleStartPos;                   ///< Cycle Start (left locator), in Quarter Note\r
+       double cycleEndPos;                             ///< Cycle End (right locator), in Quarter Note\r
+       VstInt32 timeSigNumerator;              ///< Time Signature Numerator (e.g. 3 for 3/4)\r
+       VstInt32 timeSigDenominator;    ///< Time Signature Denominator (e.g. 4 for 3/4)\r
+       VstInt32 smpteOffset;                   ///< SMPTE offset (in SMPTE subframes (bits; 1/80 of a frame)). The current SMPTE position can be calculated using #samplePos, #sampleRate, and #smpteFrameRate.\r
+       VstInt32 smpteFrameRate;                ///< @see VstSmpteFrameRate\r
+       VstInt32 samplesToNextClock;    ///< MIDI Clock Resolution (24 Per Quarter Note), can be negative (nearest clock)\r
+       VstInt32 flags;                                 ///< @see VstTimeInfoFlags\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstTimeInfo. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstTimeInfoFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstTransportChanged     = 1,           ///< indicates that play, cycle or record state has changed\r
+       kVstTransportPlaying     = 1 << 1,      ///< set if Host sequencer is currently playing\r
+       kVstTransportCycleActive = 1 << 2,      ///< set if Host sequencer is in cycle mode\r
+       kVstTransportRecording   = 1 << 3,      ///< set if Host sequencer is in record mode\r
+       kVstAutomationWriting    = 1 << 6,      ///< set if automation write mode active (record parameter changes)\r
+       kVstAutomationReading    = 1 << 7,      ///< set if automation read mode active (play parameter changes)\r
+       kVstNanosValid           = 1 << 8,      ///< VstTimeInfo::nanoSeconds valid\r
+       kVstPpqPosValid          = 1 << 9,      ///< VstTimeInfo::ppqPos valid\r
+       kVstTempoValid           = 1 << 10,     ///< VstTimeInfo::tempo valid\r
+       kVstBarsValid            = 1 << 11,     ///< VstTimeInfo::barStartPos valid\r
+       kVstCyclePosValid        = 1 << 12,     ///< VstTimeInfo::cycleStartPos and VstTimeInfo::cycleEndPos valid\r
+       kVstTimeSigValid         = 1 << 13,     ///< VstTimeInfo::timeSigNumerator and VstTimeInfo::timeSigDenominator valid\r
+       kVstSmpteValid           = 1 << 14,     ///< VstTimeInfo::smpteOffset and VstTimeInfo::smpteFrameRate valid\r
+       kVstClockValid           = 1 << 15      ///< VstTimeInfo::samplesToNextClock valid\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** SMPTE Frame Rates. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstSmpteFrameRate\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstSmpte24fps    = 0,          ///< 24 fps\r
+       kVstSmpte25fps    = 1,          ///< 25 fps\r
+       kVstSmpte2997fps  = 2,          ///< 29.97 fps\r
+       kVstSmpte30fps    = 3,          ///< 30 fps\r
+       kVstSmpte2997dfps = 4,          ///< 29.97 drop\r
+       kVstSmpte30dfps   = 5,          ///< 30 drop\r
+\r
+       kVstSmpteFilm16mm = 6,          ///< Film 16mm\r
+       kVstSmpteFilm35mm = 7,          ///< Film 35mm\r
+       kVstSmpte239fps   = 10,         ///< HDTV: 23.976 fps\r
+       kVstSmpte249fps   = 11,         ///< HDTV: 24.976 fps\r
+       kVstSmpte599fps   = 12,         ///< HDTV: 59.94 fps\r
+       kVstSmpte60fps    = 13          ///< HDTV: 60 fps\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Variable IO for Offline Processing. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstVariableIo\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       float** inputs;                                                         ///< input audio buffers\r
+       float** outputs;                                                        ///< output audio buffers\r
+       VstInt32 numSamplesInput;                                       ///< number of incoming samples\r
+       VstInt32 numSamplesOutput;                                      ///< number of outgoing samples\r
+       VstInt32* numSamplesInputProcessed;                     ///< number of samples actually processed of input\r
+       VstInt32* numSamplesOutputProcessed;            ///< number of samples actually processed of output\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Language code returned by audioMasterGetLanguage. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstHostLanguage\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstLangEnglish = 1,    ///< English\r
+       kVstLangGerman,                 ///< German\r
+       kVstLangFrench,                 ///< French\r
+       kVstLangItalian,                ///< Italian\r
+       kVstLangSpanish,                ///< Spanish\r
+       kVstLangJapanese                ///< Japanese\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** VST 2.x dispatcher Opcodes (Plug-in to Host). Extension of #AudioMasterOpcodes */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum AudioMasterOpcodesX\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       DECLARE_VST_DEPRECATED (audioMasterWantMidi) = DECLARE_VST_DEPRECATED (audioMasterPinConnected) + 2,    ///< \deprecated deprecated in VST 2.4\r
+\r
+       audioMasterGetTime,                             ///< [return value]: #VstTimeInfo* or null if not supported [value]: request mask  @see VstTimeInfoFlags @see AudioEffectX::getTimeInfo\r
+       audioMasterProcessEvents,               ///< [ptr]: pointer to #VstEvents  @see VstEvents @see AudioEffectX::sendVstEventsToHost\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterSetTime),    ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterTempoAt),    ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterGetNumAutomatableParameters),        ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterGetParameterQuantization),           ///< \deprecated deprecated in VST 2.4\r
+\r
+       audioMasterIOChanged,                   ///< [return value]: 1 if supported  @see AudioEffectX::ioChanged\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterNeedIdle),   ///< \deprecated deprecated in VST 2.4\r
+       \r
+       audioMasterSizeWindow,                  ///< [index]: new width [value]: new height [return value]: 1 if supported  @see AudioEffectX::sizeWindow\r
+       audioMasterGetSampleRate,               ///< [return value]: current sample rate  @see AudioEffectX::updateSampleRate\r
+       audioMasterGetBlockSize,                ///< [return value]: current block size  @see AudioEffectX::updateBlockSize\r
+       audioMasterGetInputLatency,             ///< [return value]: input latency in audio samples  @see AudioEffectX::getInputLatency\r
+       audioMasterGetOutputLatency,    ///< [return value]: output latency in audio samples  @see AudioEffectX::getOutputLatency\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterGetPreviousPlug),                    ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterGetNextPlug),                                ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterWillReplaceOrAccumulate),    ///< \deprecated deprecated in VST 2.4\r
+\r
+       audioMasterGetCurrentProcessLevel,      ///< [return value]: current process level  @see VstProcessLevels\r
+       audioMasterGetAutomationState,          ///< [return value]: current automation state  @see VstAutomationStates\r
+\r
+       audioMasterOfflineStart,                        ///< [index]: numNewAudioFiles [value]: numAudioFiles [ptr]: #VstAudioFile*  @see AudioEffectX::offlineStart\r
+       audioMasterOfflineRead,                         ///< [index]: bool readSource [value]: #VstOfflineOption* @see VstOfflineOption [ptr]: #VstOfflineTask*  @see VstOfflineTask @see AudioEffectX::offlineRead\r
+       audioMasterOfflineWrite,                        ///< @see audioMasterOfflineRead @see AudioEffectX::offlineRead\r
+       audioMasterOfflineGetCurrentPass,       ///< @see AudioEffectX::offlineGetCurrentPass\r
+       audioMasterOfflineGetCurrentMetaPass,   ///< @see AudioEffectX::offlineGetCurrentMetaPass\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterSetOutputSampleRate),                        ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterGetOutputSpeakerArrangement),        ///< \deprecated deprecated in VST 2.4\r
+\r
+       audioMasterGetVendorString,                     ///< [ptr]: char buffer for vendor string, limited to #kVstMaxVendorStrLen  @see AudioEffectX::getHostVendorString\r
+       audioMasterGetProductString,            ///< [ptr]: char buffer for vendor string, limited to #kVstMaxProductStrLen  @see AudioEffectX::getHostProductString\r
+       audioMasterGetVendorVersion,            ///< [return value]: vendor-specific version  @see AudioEffectX::getHostVendorVersion\r
+       audioMasterVendorSpecific,                      ///< no definition, vendor specific handling  @see AudioEffectX::hostVendorSpecific\r
+       \r
+       DECLARE_VST_DEPRECATED (audioMasterSetIcon),            ///< \deprecated deprecated in VST 2.4\r
+       \r
+       audioMasterCanDo,                                       ///< [ptr]: "can do" string [return value]: 1 for supported\r
+       audioMasterGetLanguage,                         ///< [return value]: language code  @see VstHostLanguage\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterOpenWindow),         ///< \deprecated deprecated in VST 2.4\r
+       DECLARE_VST_DEPRECATED (audioMasterCloseWindow),        ///< \deprecated deprecated in VST 2.4\r
+\r
+       audioMasterGetDirectory,                        ///< [return value]: FSSpec on MAC, else char*  @see AudioEffectX::getDirectory\r
+       audioMasterUpdateDisplay,                       ///< no arguments       \r
+       audioMasterBeginEdit,               ///< [index]: parameter index  @see AudioEffectX::beginEdit\r
+       audioMasterEndEdit,                 ///< [index]: parameter index  @see AudioEffectX::endEdit\r
+       audioMasterOpenFileSelector,            ///< [ptr]: VstFileSelect* [return value]: 1 if supported  @see AudioEffectX::openFileSelector\r
+       audioMasterCloseFileSelector,           ///< [ptr]: VstFileSelect*  @see AudioEffectX::closeFileSelector\r
+       \r
+       DECLARE_VST_DEPRECATED (audioMasterEditFile),           ///< \deprecated deprecated in VST 2.4\r
+       \r
+       DECLARE_VST_DEPRECATED (audioMasterGetChunkFile),       ///< \deprecated deprecated in VST 2.4 [ptr]: char[2048] or sizeof (FSSpec) [return value]: 1 if supported  @see AudioEffectX::getChunkFile\r
+\r
+       DECLARE_VST_DEPRECATED (audioMasterGetInputSpeakerArrangement)  ///< \deprecated deprecated in VST 2.4\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** VST 2.x dispatcher Opcodes (Host to Plug-in). Extension of #AEffectOpcodes */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum AEffectXOpcodes\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       effProcessEvents = effSetChunk + 1              ///< [ptr]: #VstEvents*  @see AudioEffectX::processEvents\r
+\r
+       , effCanBeAutomated                                             ///< [index]: parameter index [return value]: 1=true, 0=false  @see AudioEffectX::canParameterBeAutomated\r
+       , effString2Parameter                                   ///< [index]: parameter index [ptr]: parameter string [return value]: true for success  @see AudioEffectX::string2parameter\r
+\r
+       , DECLARE_VST_DEPRECATED (effGetNumProgramCategories)   ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effGetProgramNameIndexed                              ///< [index]: program index [ptr]: buffer for program name, limited to #kVstMaxProgNameLen [return value]: true for success  @see AudioEffectX::getProgramNameIndexed\r
+       \r
+       , DECLARE_VST_DEPRECATED (effCopyProgram)       ///< \deprecated deprecated in VST 2.4\r
+       , DECLARE_VST_DEPRECATED (effConnectInput)      ///< \deprecated deprecated in VST 2.4\r
+       , DECLARE_VST_DEPRECATED (effConnectOutput)     ///< \deprecated deprecated in VST 2.4\r
+       \r
+       , effGetInputProperties                                 ///< [index]: input index [ptr]: #VstPinProperties* [return value]: 1 if supported  @see AudioEffectX::getInputProperties\r
+       , effGetOutputProperties                                ///< [index]: output index [ptr]: #VstPinProperties* [return value]: 1 if supported  @see AudioEffectX::getOutputProperties\r
+       , effGetPlugCategory                                    ///< [return value]: category  @see VstPlugCategory @see AudioEffectX::getPlugCategory\r
+\r
+       , DECLARE_VST_DEPRECATED (effGetCurrentPosition)        ///< \deprecated deprecated in VST 2.4\r
+       , DECLARE_VST_DEPRECATED (effGetDestinationBuffer)      ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effOfflineNotify                                              ///< [ptr]: #VstAudioFile array [value]: count [index]: start flag  @see AudioEffectX::offlineNotify\r
+       , effOfflinePrepare                                             ///< [ptr]: #VstOfflineTask array [value]: count  @see AudioEffectX::offlinePrepare\r
+       , effOfflineRun                                                 ///< [ptr]: #VstOfflineTask array [value]: count  @see AudioEffectX::offlineRun\r
+\r
+       , effProcessVarIo                                               ///< [ptr]: #VstVariableIo*  @see AudioEffectX::processVariableIo\r
+       , effSetSpeakerArrangement                              ///< [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement*  @see AudioEffectX::setSpeakerArrangement\r
+\r
+       , DECLARE_VST_DEPRECATED (effSetBlockSizeAndSampleRate) ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effSetBypass                                                  ///< [value]: 1 = bypass, 0 = no bypass  @see AudioEffectX::setBypass\r
+       , effGetEffectName                                              ///< [ptr]: buffer for effect name, limited to #kVstMaxEffectNameLen  @see AudioEffectX::getEffectName\r
+\r
+       , DECLARE_VST_DEPRECATED (effGetErrorText)      ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effGetVendorString                                    ///< [ptr]: buffer for effect vendor string, limited to #kVstMaxVendorStrLen  @see AudioEffectX::getVendorString\r
+       , effGetProductString                                   ///< [ptr]: buffer for effect vendor string, limited to #kVstMaxProductStrLen  @see AudioEffectX::getProductString\r
+       , effGetVendorVersion                                   ///< [return value]: vendor-specific version  @see AudioEffectX::getVendorVersion\r
+       , effVendorSpecific                                             ///< no definition, vendor specific handling  @see AudioEffectX::vendorSpecific\r
+       , effCanDo                                                              ///< [ptr]: "can do" string [return value]: 0: "don't know" -1: "no" 1: "yes"  @see AudioEffectX::canDo\r
+       , effGetTailSize                                                ///< [return value]: tail size (for example the reverb time of a reverb plug-in); 0 is default (return 1 for 'no tail')\r
+\r
+       , DECLARE_VST_DEPRECATED (effIdle)                              ///< \deprecated deprecated in VST 2.4\r
+       , DECLARE_VST_DEPRECATED (effGetIcon)                   ///< \deprecated deprecated in VST 2.4\r
+       , DECLARE_VST_DEPRECATED (effSetViewPosition)   ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effGetParameterProperties                             ///< [index]: parameter index [ptr]: #VstParameterProperties* [return value]: 1 if supported  @see AudioEffectX::getParameterProperties\r
+\r
+       , DECLARE_VST_DEPRECATED (effKeysRequired)      ///< \deprecated deprecated in VST 2.4\r
+\r
+       , effGetVstVersion                                              ///< [return value]: VST version  @see AudioEffectX::getVstVersion\r
+\r
+#if VST_2_1_EXTENSIONS\r
+       , effEditKeyDown                                                ///< [index]: ASCII character [value]: virtual key [opt]: modifiers [return value]: 1 if key used  @see AEffEditor::onKeyDown\r
+       , effEditKeyUp                                                  ///< [index]: ASCII character [value]: virtual key [opt]: modifiers [return value]: 1 if key used  @see AEffEditor::onKeyUp\r
+       , effSetEditKnobMode                                    ///< [value]: knob mode 0: circular, 1: circular relativ, 2: linear (CKnobMode in VSTGUI)  @see AEffEditor::setKnobMode\r
+\r
+       , effGetMidiProgramName                                 ///< [index]: MIDI channel [ptr]: #MidiProgramName* [return value]: number of used programs, 0 if unsupported  @see AudioEffectX::getMidiProgramName\r
+       , effGetCurrentMidiProgram                              ///< [index]: MIDI channel [ptr]: #MidiProgramName* [return value]: index of current program  @see AudioEffectX::getCurrentMidiProgram\r
+       , effGetMidiProgramCategory                             ///< [index]: MIDI channel [ptr]: #MidiProgramCategory* [return value]: number of used categories, 0 if unsupported  @see AudioEffectX::getMidiProgramCategory\r
+       , effHasMidiProgramsChanged                             ///< [index]: MIDI channel [return value]: 1 if the #MidiProgramName(s) or #MidiKeyName(s) have changed  @see AudioEffectX::hasMidiProgramsChanged\r
+       , effGetMidiKeyName                                             ///< [index]: MIDI channel [ptr]: #MidiKeyName* [return value]: true if supported, false otherwise  @see AudioEffectX::getMidiKeyName\r
+       \r
+       , effBeginSetProgram                                    ///< no arguments  @see AudioEffectX::beginSetProgram\r
+       , effEndSetProgram                                              ///< no arguments  @see AudioEffectX::endSetProgram\r
+#endif // VST_2_1_EXTENSIONS\r
+\r
+#if VST_2_3_EXTENSIONS\r
+       , effGetSpeakerArrangement                              ///< [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement*  @see AudioEffectX::getSpeakerArrangement\r
+       , effShellGetNextPlugin                                 ///< [ptr]: buffer for plug-in name, limited to #kVstMaxProductStrLen [return value]: next plugin's uniqueID  @see AudioEffectX::getNextShellPlugin\r
+\r
+       , effStartProcess                                               ///< no arguments  @see AudioEffectX::startProcess\r
+       , effStopProcess                                                ///< no arguments  @see AudioEffectX::stopProcess\r
+       , effSetTotalSampleToProcess                ///< [value]: number of samples to process, offline only!  @see AudioEffectX::setTotalSampleToProcess\r
+       , effSetPanLaw                                                  ///< [value]: pan law [opt]: gain  @see VstPanLawType @see AudioEffectX::setPanLaw\r
+       \r
+       , effBeginLoadBank                                              ///< [ptr]: #VstPatchChunkInfo* [return value]: -1: bank can't be loaded, 1: bank can be loaded, 0: unsupported  @see AudioEffectX::beginLoadBank\r
+       , effBeginLoadProgram                                   ///< [ptr]: #VstPatchChunkInfo* [return value]: -1: prog can't be loaded, 1: prog can be loaded, 0: unsupported  @see AudioEffectX::beginLoadProgram\r
+#endif // VST_2_3_EXTENSIONS\r
+\r
+#if VST_2_4_EXTENSIONS\r
+       , effSetProcessPrecision                                ///< [value]: @see VstProcessPrecision  @see AudioEffectX::setProcessPrecision\r
+       , effGetNumMidiInputChannels                    ///< [return value]: number of used MIDI input channels (1-15)  @see AudioEffectX::getNumMidiInputChannels\r
+       , effGetNumMidiOutputChannels                   ///< [return value]: number of used MIDI output channels (1-15)  @see AudioEffectX::getNumMidiOutputChannels\r
+#endif // VST_2_4_EXTENSIONS\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Symbolic precision constants used for effSetProcessPrecision. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstProcessPrecision\r
+{\r
+       kVstProcessPrecision32 = 0,             ///< single precision float (32bits)\r
+       kVstProcessPrecision64                  ///< double precision (64bits)\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Parameter Properties used in #effGetParameterProperties. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstParameterProperties\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       float stepFloat;                        ///< float step\r
+       float smallStepFloat;           ///< small float step\r
+       float largeStepFloat;           ///< large float step\r
+       char label[kVstMaxLabelLen];///< parameter label\r
+       VstInt32 flags;                         ///< @see VstParameterFlags\r
+       VstInt32 minInteger;            ///< integer minimum\r
+       VstInt32 maxInteger;            ///< integer maximum\r
+       VstInt32 stepInteger;           ///< integer step\r
+       VstInt32 largeStepInteger;      ///< large integer step\r
+       char shortLabel[kVstMaxShortLabelLen];  ///< short label, recommended: 6 + delimiter\r
+\r
+       // The following are for remote controller display purposes.\r
+       // Note that the kVstParameterSupportsDisplayIndex flag must be set.\r
+       // Host can scan all parameters, and find out in what order\r
+       // to display them:\r
+\r
+       VstInt16 displayIndex;          ///< index where this parameter should be displayed (starting with 0)\r
+\r
+       // Host can also possibly display the parameter group (category), such as...\r
+       // ---------------------------\r
+       // Osc 1\r
+       // Wave  Detune  Octave  Mod\r
+       // ---------------------------\r
+       // ...if the plug-in supports it (flag #kVstParameterSupportsDisplayCategory)\r
+\r
+       VstInt16 category;                      ///< 0: no category, else group index + 1\r
+       VstInt16 numParametersInCategory;                       ///< number of parameters in category\r
+       VstInt16 reserved;                      ///< zero\r
+       char categoryLabel[kVstMaxCategLabelLen];       ///< category label, e.g. "Osc 1" \r
+\r
+       char future[16];                        ///< reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstParameterProperties. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstParameterFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstParameterIsSwitch                            = 1 << 0,      ///< parameter is a switch (on/off)\r
+       kVstParameterUsesIntegerMinMax           = 1 << 1,      ///< minInteger, maxInteger valid\r
+       kVstParameterUsesFloatStep                       = 1 << 2,      ///< stepFloat, smallStepFloat, largeStepFloat valid\r
+       kVstParameterUsesIntStep                         = 1 << 3,      ///< stepInteger, largeStepInteger valid\r
+       kVstParameterSupportsDisplayIndex        = 1 << 4,      ///< displayIndex valid\r
+       kVstParameterSupportsDisplayCategory = 1 << 5,  ///< category, etc. valid\r
+       kVstParameterCanRamp                             = 1 << 6       ///< set if parameter value can ramp up/down\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Pin Properties used in #effGetInputProperties and #effGetOutputProperties. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstPinProperties\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       char label[kVstMaxLabelLen];    ///< pin name\r
+       VstInt32 flags;                                 ///< @see VstPinPropertiesFlags\r
+       VstInt32 arrangementType;               ///< @see VstSpeakerArrangementType\r
+       char shortLabel[kVstMaxShortLabelLen];  ///< short name (recommended: 6 + delimiter)\r
+\r
+       char future[48];                                ///< reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstPinProperties. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstPinPropertiesFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstPinIsActive   = 1 << 0,             ///< pin is active, ignored by Host\r
+       kVstPinIsStereo   = 1 << 1,             ///< pin is first of a stereo pair\r
+       kVstPinUseSpeaker = 1 << 2              ///< #VstPinProperties::arrangementType is valid and can be used to get the wanted arrangement\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Plug-in Categories. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstPlugCategory\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+    kPlugCategUnknown = 0,             ///< Unknown, category not implemented\r
+    kPlugCategEffect,                  ///< Simple Effect\r
+    kPlugCategSynth,                   ///< VST Instrument (Synths, samplers,...)\r
+    kPlugCategAnalysis,                        ///< Scope, Tuner, ...\r
+    kPlugCategMastering,               ///< Dynamics, ...\r
+       kPlugCategSpacializer,          ///< Panners, ...\r
+       kPlugCategRoomFx,                       ///< Delays and Reverbs\r
+       kPlugSurroundFx,                        ///< Dedicated surround processor\r
+       kPlugCategRestoration,          ///< Denoiser, ...\r
+       kPlugCategOfflineProcess,       ///< Offline Process\r
+       kPlugCategShell,                        ///< Plug-in is container of other plug-ins  @see effShellGetNextPlugin\r
+       kPlugCategGenerator,            ///< ToneGenerator, ...\r
+\r
+       kPlugCategMaxCount                      ///< Marker to count the categories\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// MIDI Programs\r
+//-------------------------------------------------------------------------------------------------------\r
+//-------------------------------------------------------------------------------------------------------\r
+/** MIDI Program Description. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct MidiProgramName \r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 thisProgramIndex;              ///< 0 or greater: fill struct for this program index\r
+       char name[kVstMaxNameLen];              ///< program name\r
+       char midiProgram;                               ///< -1:off, 0-127\r
+       char midiBankMsb;                               ///< -1:off, 0-127\r
+       char midiBankLsb;                               ///< -1:off, 0-127\r
+       char reserved;                                  ///< zero\r
+       VstInt32 parentCategoryIndex;   ///< -1:no parent category\r
+       VstInt32 flags;                                 ///< omni etc. @see VstMidiProgramNameFlags\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in MidiProgramName. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstMidiProgramNameFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kMidiIsOmni = 1 ///< default is multi. for omni mode, channel 0 is used for inquiries and program changes\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** MIDI Program Category. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct MidiProgramCategory \r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 thisCategoryIndex;             ///< 0 or greater:  fill struct for this category index.\r
+       char name[kVstMaxNameLen];              ///< name\r
+       VstInt32 parentCategoryIndex;   ///< -1:no parent category\r
+       VstInt32 flags;                                 ///< reserved, none defined yet, zero.\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** MIDI Key Description. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct MidiKeyName \r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 thisProgramIndex;              ///< 0 or greater:  fill struct for this program index.\r
+       VstInt32 thisKeyNumber;                 ///< 0 - 127. fill struct for this key number.\r
+       char keyName[kVstMaxNameLen];   ///< key name, empty means regular key names\r
+       VstInt32 reserved;                              ///< zero\r
+       VstInt32 flags;                                 ///< reserved, none defined yet, zero.\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Surround Setup\r
+//-------------------------------------------------------------------------------------------------------\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Speaker Properties.\r
+       The origin for azimuth is right (as by math conventions dealing with radians).\r
+       The elevation origin is also right, visualizing a rotation of a circle across the\r
+       -pi/pi axis of the horizontal circle. Thus, an elevation of -pi/2 corresponds\r
+       to bottom, and a speaker standing on the left, and 'beaming' upwards would have\r
+       an azimuth of -pi, and an elevation of pi/2.\r
+       For user interface representation, grads are more likely to be used, and the\r
+       origins will obviously 'shift' accordingly. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstSpeakerProperties\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       float azimuth;          ///< unit: rad, range: -PI...PI, exception: 10.f for LFE channel\r
+       float elevation;        ///< unit: rad, range: -PI/2...PI/2, exception: 10.f for LFE channel\r
+       float radius;           ///< unit: meter, exception: 0.f for LFE channel\r
+       float reserved;         ///< zero (reserved for future use)\r
+       char name[kVstMaxNameLen];      ///< for new setups, new names should be given (L/R/C... won't do)\r
+       VstInt32 type;          ///< @see VstSpeakerType\r
+\r
+       char future[28];        ///< reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Speaker Arrangement. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstSpeakerArrangement\r
+{      \r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 type;                                          ///< e.g. #kSpeakerArr51 for 5.1  @see VstSpeakerArrangementType\r
+       VstInt32 numChannels;                           ///< number of channels in this speaker arrangement\r
+       VstSpeakerProperties speakers[8];       ///< variable sized speaker array\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Speaker Types. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstSpeakerType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kSpeakerUndefined = 0x7fffffff, ///< Undefined\r
+       kSpeakerM = 0,                                  ///< Mono (M)\r
+       kSpeakerL,                                              ///< Left (L)\r
+       kSpeakerR,                                              ///< Right (R)\r
+       kSpeakerC,                                              ///< Center (C)\r
+       kSpeakerLfe,                                    ///< Subbass (Lfe)\r
+       kSpeakerLs,                                             ///< Left Surround (Ls)\r
+       kSpeakerRs,                                             ///< Right Surround (Rs)\r
+       kSpeakerLc,                                             ///< Left of Center (Lc)\r
+       kSpeakerRc,                                             ///< Right of Center (Rc)\r
+       kSpeakerS,                                              ///< Surround (S)\r
+       kSpeakerCs = kSpeakerS,                 ///< Center of Surround (Cs) = Surround (S)\r
+       kSpeakerSl,                                             ///< Side Left (Sl)\r
+       kSpeakerSr,                                             ///< Side Right (Sr)\r
+       kSpeakerTm,                                             ///< Top Middle (Tm)\r
+       kSpeakerTfl,                                    ///< Top Front Left (Tfl)\r
+       kSpeakerTfc,                                    ///< Top Front Center (Tfc)\r
+       kSpeakerTfr,                                    ///< Top Front Right (Tfr)\r
+       kSpeakerTrl,                                    ///< Top Rear Left (Trl)\r
+       kSpeakerTrc,                                    ///< Top Rear Center (Trc)\r
+       kSpeakerTrr,                                    ///< Top Rear Right (Trr)\r
+       kSpeakerLfe2                                    ///< Subbass 2 (Lfe2)\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** User-defined speaker types, to be extended in the negative range.\r
+       Will be handled as their corresponding speaker types with abs values:\r
+       e.g abs(#kSpeakerU1) == #kSpeakerL, abs(#kSpeakerU2) == #kSpeakerR) */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstUserSpeakerType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kSpeakerU32 = -32,      \r
+       kSpeakerU31,                    \r
+       kSpeakerU30,                    \r
+       kSpeakerU29,                    \r
+       kSpeakerU28,                    \r
+       kSpeakerU27,                    \r
+       kSpeakerU26,                    \r
+       kSpeakerU25,                    \r
+       kSpeakerU24,                    \r
+       kSpeakerU23,                    \r
+       kSpeakerU22,                    \r
+       kSpeakerU21,                    \r
+       kSpeakerU20,                    ///< == #kSpeakerLfe2\r
+       kSpeakerU19,                    ///< == #kSpeakerTrr\r
+       kSpeakerU18,                    ///< == #kSpeakerTrc\r
+       kSpeakerU17,                    ///< == #kSpeakerTrl\r
+       kSpeakerU16,                    ///< == #kSpeakerTfr\r
+       kSpeakerU15,                    ///< == #kSpeakerTfc\r
+       kSpeakerU14,                    ///< == #kSpeakerTfl\r
+       kSpeakerU13,                    ///< == #kSpeakerTm\r
+       kSpeakerU12,                    ///< == #kSpeakerSr\r
+       kSpeakerU11,                    ///< == #kSpeakerSl\r
+       kSpeakerU10,                    ///< == #kSpeakerCs\r
+       kSpeakerU9,                             ///< == #kSpeakerS\r
+       kSpeakerU8,                             ///< == #kSpeakerRc\r
+       kSpeakerU7,                             ///< == #kSpeakerLc\r
+       kSpeakerU6,                             ///< == #kSpeakerRs\r
+       kSpeakerU5,                             ///< == #kSpeakerLs\r
+       kSpeakerU4,                             ///< == #kSpeakerLfe\r
+       kSpeakerU3,                             ///< == #kSpeakerC\r
+       kSpeakerU2,                             ///< == #kSpeakerR\r
+       kSpeakerU1                              ///< == #kSpeakerL\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Speaker Arrangement Types*/\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstSpeakerArrangementType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kSpeakerArrUserDefined = -2,///< user defined\r
+       kSpeakerArrEmpty = -1,          ///< empty arrangement\r
+       kSpeakerArrMono  =  0,          ///< M\r
+       kSpeakerArrStereo,                      ///< L R\r
+       kSpeakerArrStereoSurround,      ///< Ls Rs\r
+       kSpeakerArrStereoCenter,        ///< Lc Rc\r
+       kSpeakerArrStereoSide,          ///< Sl Sr\r
+       kSpeakerArrStereoCLfe,          ///< C Lfe\r
+       kSpeakerArr30Cine,                      ///< L R C\r
+       kSpeakerArr30Music,                     ///< L R S\r
+       kSpeakerArr31Cine,                      ///< L R C Lfe\r
+       kSpeakerArr31Music,                     ///< L R Lfe S\r
+       kSpeakerArr40Cine,                      ///< L R C   S (LCRS)\r
+       kSpeakerArr40Music,                     ///< L R Ls  Rs (Quadro)\r
+       kSpeakerArr41Cine,                      ///< L R C   Lfe S (LCRS+Lfe)\r
+       kSpeakerArr41Music,                     ///< L R Lfe Ls Rs (Quadro+Lfe)\r
+       kSpeakerArr50,                          ///< L R C Ls  Rs \r
+       kSpeakerArr51,                          ///< L R C Lfe Ls Rs\r
+       kSpeakerArr60Cine,                      ///< L R C   Ls  Rs Cs\r
+       kSpeakerArr60Music,                     ///< L R Ls  Rs  Sl Sr \r
+       kSpeakerArr61Cine,                      ///< L R C   Lfe Ls Rs Cs\r
+       kSpeakerArr61Music,                     ///< L R Lfe Ls  Rs Sl Sr \r
+       kSpeakerArr70Cine,                      ///< L R C Ls  Rs Lc Rc \r
+       kSpeakerArr70Music,                     ///< L R C Ls  Rs Sl Sr\r
+       kSpeakerArr71Cine,                      ///< L R C Lfe Ls Rs Lc Rc\r
+       kSpeakerArr71Music,                     ///< L R C Lfe Ls Rs Sl Sr\r
+       kSpeakerArr80Cine,                      ///< L R C Ls  Rs Lc Rc Cs\r
+       kSpeakerArr80Music,                     ///< L R C Ls  Rs Cs Sl Sr\r
+       kSpeakerArr81Cine,                      ///< L R C Lfe Ls Rs Lc Rc Cs\r
+       kSpeakerArr81Music,                     ///< L R C Lfe Ls Rs Cs Sl Sr \r
+       kSpeakerArr102,                         ///< L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Lfe2\r
+       kNumSpeakerArr\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Offline Processing\r
+//-------------------------------------------------------------------------------------------------------\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Offline Task Description. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstOfflineTask\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       char processName[96];                   ///< set by plug-in\r
+\r
+       // audio access\r
+       double readPosition;                    ///< set by plug-in/Host\r
+       double writePosition;                   ///< set by plug-in/Host\r
+       VstInt32 readCount;                             ///< set by plug-in/Host\r
+       VstInt32 writeCount;                    ///< set by plug-in\r
+       VstInt32 sizeInputBuffer;               ///< set by Host\r
+       VstInt32 sizeOutputBuffer;              ///< set by Host\r
+       void* inputBuffer;                              ///< set by Host\r
+       void* outputBuffer;                             ///< set by Host\r
+       double positionToProcessFrom;   ///< set by Host\r
+       double numFramesToProcess;              ///< set by Host\r
+       double maxFramesToWrite;                ///< set by plug-in\r
+\r
+       // other data access\r
+       void* extraBuffer;                              ///< set by plug-in\r
+       VstInt32 value;                                 ///< set by Host or plug-in\r
+       VstInt32 index;                                 ///< set by Host or plug-in\r
+\r
+       // file attributes\r
+       double numFramesInSourceFile;   ///< set by Host\r
+       double sourceSampleRate;                ///< set by Host or plug-in\r
+       double destinationSampleRate;   ///< set by Host or plug-in\r
+       VstInt32 numSourceChannels;             ///< set by Host or plug-in\r
+       VstInt32 numDestinationChannels;///< set by Host or plug-in\r
+       VstInt32 sourceFormat;                  ///< set by Host\r
+       VstInt32 destinationFormat;             ///< set by plug-in\r
+       char outputText[512];                   ///< set by plug-in or Host\r
+\r
+       // progress notification\r
+       double progress;                                ///< set by plug-in\r
+       VstInt32 progressMode;                  ///< Reserved for future use\r
+       char progressText[100];                 ///< set by plug-in\r
+\r
+       VstInt32 flags;                                 ///< set by Host and plug-in; see enum #VstOfflineTaskFlags\r
+       VstInt32 returnValue;                   ///< Reserved for future use\r
+       void* hostOwned;                                ///< set by Host\r
+       void* plugOwned;                                ///< set by plug-in\r
+\r
+       char future[1024];                              ///< Reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstOfflineTask. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstOfflineTaskFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstOfflineUnvalidParameter     = 1 << 0,       ///< set by Host\r
+       kVstOfflineNewFile                      = 1 << 1,       ///< set by Host\r
+\r
+       kVstOfflinePlugError            = 1 << 10,      ///< set by plug-in\r
+       kVstOfflineInterleavedAudio     = 1 << 11,      ///< set by plug-in\r
+       kVstOfflineTempOutputFile       = 1 << 12,      ///< set by plug-in\r
+       kVstOfflineFloatOutputFile      = 1 << 13,      ///< set by plug-in\r
+       kVstOfflineRandomWrite          = 1 << 14,      ///< set by plug-in\r
+       kVstOfflineStretch                      = 1 << 15,      ///< set by plug-in\r
+       kVstOfflineNoThread                     = 1 << 16       ///< set by plug-in\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Option passed to #offlineRead/#offlineWrite. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstOfflineOption\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+   kVstOfflineAudio,           ///< reading/writing audio samples\r
+   kVstOfflinePeaks,           ///< reading graphic representation\r
+   kVstOfflineParameter,       ///< reading/writing parameters\r
+   kVstOfflineMarker,          ///< reading/writing marker\r
+   kVstOfflineCursor,          ///< reading/moving edit cursor\r
+   kVstOfflineSelection,       ///< reading/changing selection\r
+   kVstOfflineQueryFiles       ///< to request the Host to call asynchronously #offlineNotify\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Structure passed to #offlineNotify and #offlineStart */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstAudioFile\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 flags;                                 ///< see enum #VstAudioFileFlags\r
+       void* hostOwned;                                ///< any data private to Host\r
+       void* plugOwned;                                ///< any data private to plug-in\r
+       char name[kVstMaxFileNameLen];  ///< file title\r
+       VstInt32 uniqueId;                              ///< uniquely identify a file during a session\r
+       double sampleRate;                              ///< file sample rate\r
+       VstInt32 numChannels;                   ///< number of channels (1 for mono, 2 for stereo...)\r
+       double numFrames;                               ///< number of frames in the audio file\r
+       VstInt32 format;                                ///< Reserved for future use\r
+       double editCursorPosition;              ///< -1 if no such cursor\r
+       double selectionStart;                  ///< frame index of first selected frame, or -1\r
+       double selectionSize;                   ///< number of frames in selection, or 0\r
+       VstInt32 selectedChannelsMask;  ///< 1 bit per channel\r
+       VstInt32 numMarkers;                    ///< number of markers in the file\r
+       VstInt32 timeRulerUnit;                 ///< see doc for possible values\r
+       double timeRulerOffset;                 ///< offset in time ruler (positive or negative)\r
+       double tempo;                                   ///< as BPM (Beats Per Minute)\r
+       VstInt32 timeSigNumerator;              ///< time signature numerator\r
+       VstInt32 timeSigDenominator;    ///< time signature denominator\r
+       VstInt32 ticksPerBlackNote;             ///< resolution\r
+       VstInt32 smpteFrameRate;                ///< SMPTE rate (set as in #VstTimeInfo)\r
+\r
+       char future[64];                                ///< Reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Flags used in #VstAudioFile. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstAudioFileFlags\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstOfflineReadOnly                             = 1 << 0,       ///< set by Host (in call #offlineNotify)\r
+       kVstOfflineNoRateConversion             = 1 << 1,       ///< set by Host (in call #offlineNotify)\r
+       kVstOfflineNoChannelChange              = 1 << 2,       ///< set by Host (in call #offlineNotify)\r
+\r
+       kVstOfflineCanProcessSelection  = 1 << 10,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineNoCrossfade                  = 1 << 11,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineWantRead                             = 1 << 12,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineWantWrite                    = 1 << 13,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineWantWriteMarker              = 1 << 14,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineWantMoveCursor               = 1 << 15,      ///< set by plug-in (in call #offlineStart)\r
+       kVstOfflineWantSelect                   = 1 << 16       ///< set by plug-in (in call #offlineStart)\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Audio file marker. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstAudioFileMarker\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       double position;                ///< marker position\r
+       char name[32];                  ///< marker name\r
+       VstInt32 type;                  ///< marker type\r
+       VstInt32 id;                    ///< marker identifier\r
+       VstInt32 reserved;              ///< reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+// Others\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** \deprecated Structure used for #openWindow and #closeWindow (deprecated in VST 2.4). */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct DECLARE_VST_DEPRECATED (VstWindow)\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       char title[128];\r
+       VstInt16 xPos;\r
+       VstInt16 yPos;\r
+       VstInt16 width;\r
+       VstInt16 height;\r
+       VstInt32 style;\r
+       void* parent;\r
+       void* userHandle;\r
+       void* winHandle;\r
+\r
+       char future[104];\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Structure used for keyUp/keyDown. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstKeyCode\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 character;             ///< ASCII character\r
+       unsigned char virt;     ///< @see VstVirtualKey\r
+       unsigned char modifier; ///< @see VstModifierKey\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Platform-independent definition of Virtual Keys (used in #VstKeyCode). */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstVirtualKey \r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VKEY_BACK = 1, \r
+       VKEY_TAB, \r
+       VKEY_CLEAR, \r
+       VKEY_RETURN, \r
+       VKEY_PAUSE, \r
+       VKEY_ESCAPE, \r
+       VKEY_SPACE, \r
+       VKEY_NEXT, \r
+       VKEY_END, \r
+       VKEY_HOME, \r
+       VKEY_LEFT, \r
+       VKEY_UP, \r
+       VKEY_RIGHT, \r
+       VKEY_DOWN, \r
+       VKEY_PAGEUP, \r
+       VKEY_PAGEDOWN, \r
+       VKEY_SELECT, \r
+       VKEY_PRINT, \r
+       VKEY_ENTER, \r
+       VKEY_SNAPSHOT, \r
+       VKEY_INSERT, \r
+       VKEY_DELETE, \r
+       VKEY_HELP, \r
+       VKEY_NUMPAD0, \r
+       VKEY_NUMPAD1, \r
+       VKEY_NUMPAD2, \r
+       VKEY_NUMPAD3, \r
+       VKEY_NUMPAD4, \r
+       VKEY_NUMPAD5, \r
+       VKEY_NUMPAD6, \r
+       VKEY_NUMPAD7, \r
+       VKEY_NUMPAD8, \r
+       VKEY_NUMPAD9, \r
+       VKEY_MULTIPLY, \r
+       VKEY_ADD, \r
+       VKEY_SEPARATOR, \r
+       VKEY_SUBTRACT, \r
+       VKEY_DECIMAL, \r
+       VKEY_DIVIDE, \r
+       VKEY_F1, \r
+       VKEY_F2, \r
+       VKEY_F3, \r
+       VKEY_F4, \r
+       VKEY_F5, \r
+       VKEY_F6, \r
+       VKEY_F7, \r
+       VKEY_F8, \r
+       VKEY_F9, \r
+       VKEY_F10, \r
+       VKEY_F11, \r
+       VKEY_F12, \r
+       VKEY_NUMLOCK, \r
+       VKEY_SCROLL,\r
+       VKEY_SHIFT,\r
+       VKEY_CONTROL,\r
+       VKEY_ALT,\r
+       VKEY_EQUALS\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Modifier flags used in #VstKeyCode. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstModifierKey\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       MODIFIER_SHIFT     = 1<<0, ///< Shift\r
+       MODIFIER_ALTERNATE = 1<<1, ///< Alt\r
+       MODIFIER_COMMAND   = 1<<2, ///< Control on Mac\r
+       MODIFIER_CONTROL   = 1<<3  ///< Ctrl on PC, Apple on Mac\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** File filter used in #VstFileSelect. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstFileType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       char name[128];                         ///< display name\r
+       char macType[8];                        ///< MacOS type\r
+       char dosType[8];                        ///< Windows file extension\r
+       char unixType[8];                       ///< Unix file extension\r
+       char mimeType1[128];            ///< MIME type\r
+       char mimeType2[128];            ///< additional MIME type\r
+\r
+       VstFileType (const char* _name = 0, const char* _macType = 0, const char* _dosType = 0,\r
+                                const char* _unixType = 0, const char* _mimeType1 = 0, const char* _mimeType2 = 0)\r
+       {\r
+               vst_strncpy (name, _name ? _name : "", 127);\r
+               vst_strncpy (macType, _macType ? _macType : "", 7);\r
+               vst_strncpy (dosType, _dosType ? _dosType : "", 7);\r
+               vst_strncpy (unixType, _unixType ? _unixType : "", 7);\r
+               vst_strncpy (mimeType1, _mimeType1 ? _mimeType1 : "", 127);\r
+               vst_strncpy (mimeType2, _mimeType2 ? _mimeType2 : "", 127);\r
+       }\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** File Selector Description used in #audioMasterOpenFileSelector. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstFileSelect\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 command;           ///< @see VstFileSelectCommand\r
+       VstInt32 type;              ///< @see VstFileSelectType\r
+       VstInt32 macCreator;        ///< optional: 0 = no creator\r
+       VstInt32 nbFileTypes;       ///< number of fileTypes\r
+       VstFileType* fileTypes;         ///< list of fileTypes  @see VstFileType\r
+       char title[1024];                       ///< text to display in file selector's title\r
+       char* initialPath;                      ///< initial path\r
+       char* returnPath;                       ///< use with #kVstFileLoad and #kVstDirectorySelect. null: Host allocates memory, plug-in must call #closeOpenFileSelector!\r
+       VstInt32 sizeReturnPath;        ///< size of allocated memory for return paths\r
+       char** returnMultiplePaths; ///< use with kVstMultipleFilesLoad. Host allocates memory, plug-in must call #closeOpenFileSelector!\r
+       VstInt32 nbReturnPath;          ///< number of selected paths\r
+       VstIntPtr reserved;                     ///< reserved for Host application\r
+\r
+       char future[116];                       ///< reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Command constants used in #VstFileSelect structure. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstFileSelectCommand\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstFileLoad = 0,               ///< for loading a file\r
+       kVstFileSave,                   ///< for saving a file\r
+       kVstMultipleFilesLoad,  ///< for loading multiple files\r
+       kVstDirectorySelect             ///< for selecting a directory/folder\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Types used in #VstFileSelect structure. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstFileSelectType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstFileType = 0                ///< regular file selector\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Structure used for #effBeginLoadBank/#effBeginLoadProgram. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct VstPatchChunkInfo\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 version;                       ///< Format Version (should be 1)\r
+       VstInt32 pluginUniqueID;        ///< UniqueID of the plug-in\r
+       VstInt32 pluginVersion;         ///< Plug-in Version\r
+       VstInt32 numElements;           ///< Number of Programs (Bank) or Parameters (Program)\r
+\r
+       char future[48];                        ///< Reserved for future use\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** PanLaw Type. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstPanLawType\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kLinearPanLaw = 0,      ///< L = pan * M; R = (1 - pan) * M;\r
+       kEqualPowerPanLaw       ///< L = pow (pan, 0.5) * M; R = pow ((1 - pan), 0.5) * M;\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Process Levels returned by #audioMasterGetCurrentProcessLevel. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstProcessLevels\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstProcessLevelUnknown = 0,    ///< not supported by Host\r
+       kVstProcessLevelUser,                   ///< 1: currently in user thread (GUI)\r
+       kVstProcessLevelRealtime,               ///< 2: currently in audio thread (where process is called)\r
+       kVstProcessLevelPrefetch,               ///< 3: currently in 'sequencer' thread (MIDI, timer etc)\r
+       kVstProcessLevelOffline                 ///< 4: currently offline processing and thus in user thread\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Automation States returned by #audioMasterGetAutomationState. */\r
+//-------------------------------------------------------------------------------------------------------\r
+enum VstAutomationStates\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       kVstAutomationUnsupported = 0,  ///< not supported by Host\r
+       kVstAutomationOff,                              ///< off\r
+       kVstAutomationRead,                             ///< read\r
+       kVstAutomationWrite,                    ///< write\r
+       kVstAutomationReadWrite                 ///< read and write\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+#if TARGET_API_MAC_CARBON\r
+       #pragma options align=reset\r
+#elif defined(WIN32) || defined(__FLAT__) || defined(__GNUC__)\r
+       #pragma pack(pop)\r
+#elif defined __BORLANDC__\r
+       #pragma -a-\r
+#endif\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#endif //__aeffectx__\r
diff --git a/src/deps/vst/vstfxstore.h b/src/deps/vst/vstfxstore.h
new file mode 100644 (file)
index 0000000..d7d60f4
--- /dev/null
@@ -0,0 +1,106 @@
+//-------------------------------------------------------------------------------------------------------\r
+// VST Plug-Ins SDK\r
+// Version 2.4         $Date: 2006/02/09 11:05:51 $\r
+//\r
+// Category     : VST 2.x Interfaces\r
+// Filename     : vstfxstore.h\r
+// Created by   : Steinberg Media Technologies\r
+// Description  : Definition of Program (fxp) and Bank (fxb) structures\r
+//\r
+// © 2006, Steinberg Media Technologies, All Rights Reserved\r
+//-------------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __vstfxstore__\r
+#define __vstfxstore__\r
+\r
+#ifndef __aeffect__\r
+#include "aeffect.h"\r
+#endif\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Root chunk identifier for Programs (fxp) and Banks (fxb). */\r
+#define cMagic                         'CcnK'\r
+\r
+/** Regular Program (fxp) identifier. */\r
+#define fMagic                         'FxCk'\r
+\r
+/** Regular Bank (fxb) identifier. */\r
+#define bankMagic                      'FxBk'\r
+\r
+/** Program (fxp) identifier for opaque chunk data. */\r
+#define chunkPresetMagic       'FPCh'\r
+\r
+/** Bank (fxb) identifier for opaque chunk data. */\r
+#define chunkBankMagic         'FBCh'\r
+\r
+/* \r
+       Note: The C data structures below are for illustration only. You can not read/write them directly.\r
+       The byte order on disk of fxp and fxb files is Big Endian. You have to swap integer\r
+       and floating-point values on Little Endian platforms (Windows, MacIntel)!\r
+*/\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Program (fxp) structure. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct fxProgram\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 chunkMagic;            ///< 'CcnK'\r
+       VstInt32 byteSize;                      ///< size of this chunk, excl. magic + byteSize\r
+\r
+       VstInt32 fxMagic;                       ///< 'FxCk' (regular) or 'FPCh' (opaque chunk)\r
+       VstInt32 version;                       ///< format version (currently 1)\r
+       VstInt32 fxID;                          ///< fx unique ID\r
+       VstInt32 fxVersion;                     ///< fx version\r
+\r
+       VstInt32 numParams;                     ///< number of parameters\r
+       char prgName[28];                       ///< program name (null-terminated ASCII string)\r
+\r
+       union\r
+       {\r
+               float params[1];                ///< variable sized array with parameter values\r
+               struct \r
+               {\r
+                       VstInt32 size;          ///< size of program data\r
+                       char chunk[1];          ///< variable sized array with opaque program data\r
+               } data;                                 ///< program chunk data\r
+       } content;                                      ///< program content depending on fxMagic\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+//-------------------------------------------------------------------------------------------------------\r
+/** Bank (fxb) structure. */\r
+//-------------------------------------------------------------------------------------------------------\r
+struct fxBank\r
+{\r
+//-------------------------------------------------------------------------------------------------------\r
+       VstInt32 chunkMagic;            ///< 'CcnK'\r
+       VstInt32 byteSize;                      ///< size of this chunk, excl. magic + byteSize\r
+\r
+       VstInt32 fxMagic;                       ///< 'FxBk' (regular) or 'FBCh' (opaque chunk)\r
+       VstInt32 version;                       ///< format version (1 or 2)\r
+       VstInt32 fxID;                          ///< fx unique ID\r
+       VstInt32 fxVersion;                     ///< fx version\r
+\r
+       VstInt32 numPrograms;           ///< number of programs\r
+\r
+#if VST_2_4_EXTENSIONS\r
+       VstInt32 currentProgram;        ///< version 2: current program number\r
+       char future[124];                       ///< reserved, should be zero\r
+#else\r
+       char future[128];                       ///< reserved, should be zero\r
+#endif\r
+\r
+       union\r
+       {\r
+               fxProgram programs[1];  ///< variable number of programs\r
+               struct\r
+               {\r
+                       VstInt32 size;          ///< size of bank data\r
+                       char chunk[1];          ///< variable sized array with opaque bank data\r
+               } data;                                 ///< bank chunk data\r
+       } content;                                      ///< bank content depending on fxMagic\r
+//-------------------------------------------------------------------------------------------------------\r
+};\r
+\r
+#endif // __vstfxstore__\r
diff --git a/src/ext/giada.ico b/src/ext/giada.ico
new file mode 100644 (file)
index 0000000..e0a90bd
Binary files /dev/null and b/src/ext/giada.ico differ
diff --git a/src/ext/resource.h b/src/ext/resource.h
new file mode 100644 (file)
index 0000000..d771ba8
--- /dev/null
@@ -0,0 +1 @@
+#define IDI_ICON1 101
\ No newline at end of file
diff --git a/src/ext/resource.rc b/src/ext/resource.rc
new file mode 100644 (file)
index 0000000..fb0be40
--- /dev/null
@@ -0,0 +1,2 @@
+#include "resource.h"
+IDI_ICON1 ICON DISCARDABLE "giada.ico"
\ No newline at end of file
diff --git a/src/gd_about.cpp b/src/gd_about.cpp
deleted file mode 100644 (file)
index 8caa7a0..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_about
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_about.h"
-#include "conf.h"
-#include "const.h"
-#include "kernelAudio.h"
-#include "kernelMidi.h"
-#include "ge_mixed.h"
-#include "graphics.h"
-#include "gui_utils.h"
-
-
-extern Conf G_Conf;
-
-
-gdAbout::gdAbout()
-#ifdef WITH_VST
-: gWindow(340, 405, "About Giada") {
-#else
-: gWindow(340, 320, "About Giada") {
-#endif
-
-       if (G_Conf.aboutX)
-               resize(G_Conf.aboutX, G_Conf.aboutY, w(), h());
-
-       set_modal();
-
-       logo  = new gBox(8, 10, 324, 86);
-       text  = new gBox(8, 120, 324, 145);
-       close = new gClick(252, h()-28, 80, 20, "Close");
-#ifdef WITH_VST
-       vstLogo = new gBox(8, 265, 324, 50);
-       vstText = new gBox(8, 315, 324, 46);
-#endif
-       end();
-
-       logo->image(new Fl_Pixmap(giada_logo_xpm));
-       text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
-
-       char message[512];
-       sprintf(
-         message,
-         "Version " VERSIONE " (" __DATE__ ")\n\n"
-               "Developed by Monocasual\n"
-               "Based on FLTK (%d.%d.%d), RtAudio (%s),\n"
-               "RtMidi (%s), libsamplerate and libsndfile\n\n"
-               "Released under the terms of the GNU General\n"
-               "Public License (GPL v3)\n\n"
-               "News, infos, contacts and documentation:\n"
-               "www.giadamusic.com",
-               FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, 
-               kernelAudio::getRtAudioVersion().c_str(),
-               kernelMidi::getRtMidiVersion().c_str());
-
-       int tw = 0;
-       int th = 0;
-       fl_measure(message, tw, th);
-       text->copy_label(message);
-       text->size(text->w(), th);
-
-#ifdef WITH_VST
-       vstLogo->image(new Fl_Pixmap(vstLogo_xpm));
-       vstLogo->position(vstLogo->x(), text->y()+text->h()+8);
-       vstText->label(
-               "VST Plug-In Technology by Steinberg\n"
-               "VST is a trademark of Steinberg\nMedia Technologies GmbH"
-       );
-       vstText->position(vstText->x(), vstLogo->y()+vstLogo->h());
-
-#endif
-
-       close->callback(cb_close, (void*)this);
-       gu_setFavicon(this);
-       setId(WID_ABOUT);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdAbout::~gdAbout() {
-       G_Conf.aboutX = x();
-       G_Conf.aboutY = y();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdAbout::cb_close(Fl_Widget *w, void *p) { ((gdAbout*)p)->__cb_close(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdAbout::__cb_close() {
-       do_callback();
-}
diff --git a/src/gd_about.h b/src/gd_about.h
deleted file mode 100644 (file)
index 695a91e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_about
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_ABOUT_H
-#define GD_ABOUT_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "ge_window.h"
-
-
-class gdAbout : public gWindow {
-private:
-       class gBox       *logo;
-       class gBox       *text;
-       class gClick *close;
-
-#ifdef WITH_VST
-       class gBox  *vstText;
-       class gBox  *vstLogo;
-#endif
-
-public:
-       gdAbout();
-       ~gdAbout();
-
-       static void cb_close(Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-};
-
-#endif
diff --git a/src/gd_actionEditor.cpp b/src/gd_actionEditor.cpp
deleted file mode 100644 (file)
index 9737e9a..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_actionEditor
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <math.h>
-#include "gd_actionEditor.h"
-#include "ge_actionChannel.h"
-#include "ge_muteChannel.h"
-#include "ge_envelopeChannel.h"
-#include "ge_pianoRoll.h"
-#include "gui_utils.h"
-#include "graphics.h"
-#include "mixer.h"
-#include "recorder.h"
-#include "conf.h"
-#include "ge_mixed.h"
-#include "channel.h"
-#include "sampleChannel.h"
-
-
-extern Mixer G_Mixer;
-extern Conf     G_Conf;
-
-
-gdActionEditor::gdActionEditor(Channel *chan)
-       :       gWindow(640, 284),
-               chan   (chan),
-               zoom   (100),
-               coverX (0)
-{
-       if (G_Conf.actionEditorW) {
-               resize(G_Conf.actionEditorX, G_Conf.actionEditorY, G_Conf.actionEditorW, G_Conf.actionEditorH);
-               zoom = G_Conf.actionEditorZoom;
-       }
-
-       totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom);
-
-       /* container with zoom buttons and the action type selector. Scheme of
-        * the resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
-
-       Fl_Group *upperArea = new Fl_Group(8, 8, w()-16, 20);
-
-       upperArea->begin();
-
-       if (chan->type == CHANNEL_SAMPLE) {
-         actionType = new gChoice(8, 8, 80, 20);
-         gridTool   = new gGridTool(actionType->x()+actionType->w()+4, 8, this);
-               actionType->add("key press");
-               actionType->add("key release");
-               actionType->add("kill chan");
-               actionType->value(0);
-
-               SampleChannel *ch = (SampleChannel*) chan;
-               if (ch->mode == SINGLE_PRESS || ch->mode & LOOP_ANY)
-               actionType->deactivate();
-       }
-       else {
-               gridTool = new gGridTool(8, 8, this);
-       }
-
-               gBox *b1   = new gBox(gridTool->x()+gridTool->w()+4, 8, 300, 20);    // padding actionType - zoomButtons
-               zoomIn     = new gClick(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
-               zoomOut    = new gClick(w()-8-20,   8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
-       upperArea->end();
-       upperArea->resizable(b1);
-
-       zoomIn->callback(cb_zoomIn, (void*)this);
-       zoomOut->callback(cb_zoomOut, (void*)this);
-
-       /* main scroller: contains all widgets */
-
-       scroller = new gScroll(8, 36, w()-16, h()-44);
-
-       if (chan->type == CHANNEL_SAMPLE) {
-
-               SampleChannel *ch = (SampleChannel*) chan;
-
-               ac = new gActionChannel     (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch);
-               mc = new gMuteChannel       (scroller->x(), ac->y()+ac->h()+8, this);
-               vc = new gEnvelopeChannel   (scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume");
-               scroller->add(ac);
-               //scroller->add(new gResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8));
-               scroller->add(mc);
-               //scroller->add(new gResizerBar(mc->x(), mc->y()+mc->h(), scroller->w(), 8));
-               scroller->add(vc);
-               //scroller->add(new gResizerBar(vc->x(), vc->y()+vc->h(), scroller->w(), 8));
-
-               /* fill volume envelope with actions from recorder */
-
-               vc->fill();
-
-               /* if channel is LOOP_ANY, deactivate it: a loop mode channel cannot
-                * hold keypress/keyrelease actions */
-
-               if (ch->mode & LOOP_ANY)
-                       ac->deactivate();
-       }
-       else {
-               pr = new gPianoRollContainer(scroller->x(), upperArea->y()+upperArea->h()+8, this);
-               scroller->add(pr);
-               scroller->add(new gResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8));
-       }
-
-       end();
-
-       /* compute values */
-
-       update();
-       gridTool->calc();
-
-       gu_setFavicon(this);
-
-       char buf[256];
-       sprintf(buf, "Edit Actions in Channel %d", chan->index+1);
-       label(buf);
-
-       set_non_modal();
-       size_range(640, 284);
-       resizable(scroller);
-
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdActionEditor::~gdActionEditor() {
-       G_Conf.actionEditorX = x();
-       G_Conf.actionEditorY = y();
-       G_Conf.actionEditorW = w();
-       G_Conf.actionEditorH = h();
-       G_Conf.actionEditorZoom = zoom;
-
-       /** CHECKME - missing clear() ? */
-
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdActionEditor::cb_zoomIn(Fl_Widget *w, void *p)  { ((gdActionEditor*)p)->__cb_zoomIn(); }
-void gdActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomOut(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdActionEditor::__cb_zoomIn() {
-
-       /* zoom 50: empirical value, to avoid a totalWidth > 16 bit signed
-        * (32767 max), unsupported by FLTK 1.3.x */
-
-       if (zoom <= 50)
-               return;
-
-       zoom /= 2;
-
-       update();
-
-       if (chan->type == CHANNEL_SAMPLE) {
-               ac->size(totalWidth, ac->h());
-               mc->size(totalWidth, mc->h());
-               vc->size(totalWidth, vc->h());
-               ac->updateActions();
-               mc->updateActions();
-               vc->updateActions();
-       }
-       else {
-               pr->size(totalWidth, pr->h());
-               pr->updateActions();
-       }
-
-       /* scroll to pointer */
-
-       int shift = Fl::event_x() + scroller->xposition();
-       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
-
-       /* update all underlying widgets */
-
-       gridTool->calc();
-       scroller->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdActionEditor::__cb_zoomOut() {
-
-       zoom *= 2;
-
-       update();
-
-       if (chan->type == CHANNEL_SAMPLE) {
-               ac->size(totalWidth, ac->h());
-               mc->size(totalWidth, mc->h());
-               vc->size(totalWidth, vc->h());
-               ac->updateActions();
-               mc->updateActions();
-               vc->updateActions();
-       }
-       else {
-               pr->size(totalWidth, pr->h());
-               pr->updateActions();
-       }
-
-       /* scroll to pointer */
-
-       int shift = (Fl::event_x() + scroller->xposition()) / -2;
-       if (scroller->xposition() + shift < 0)
-                       shift = 0;
-       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
-
-       /* update all underlying widgets */
-
-       gridTool->calc();
-       scroller->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdActionEditor::update() {
-       totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom);
-       if (totalWidth < scroller->w()) {
-               totalWidth = scroller->w();
-               zoom = (int) ceilf(G_Mixer.framesInSequencer / (float) totalWidth);
-               scroller->scroll_to(0, scroller->yposition());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gdActionEditor::handle(int e) {
-       int ret = Fl_Group::handle(e);
-       switch (e) {
-               case FL_MOUSEWHEEL: {
-                       Fl::event_dy() == -1 ? __cb_zoomIn() : __cb_zoomOut();
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gdActionEditor::getActionType() {
-       if (actionType->value() == 0)
-               return ACTION_KEYPRESS;
-       else
-       if (actionType->value() == 1)
-               return ACTION_KEYREL;
-       else
-       if (actionType->value() == 2)
-               return ACTION_KILLCHAN;
-       else
-               return -1;
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gGridTool::gGridTool(int x, int y, gdActionEditor *parent)
-       :       Fl_Group(x, y, 80, 20), parent(parent)
-{
-       gridType = new gChoice(x, y, 40, 20);
-       gridType->add("1");
-       gridType->add("2");
-       gridType->add("3");
-       gridType->add("4");
-       gridType->add("6");
-       gridType->add("8");
-       gridType->add("16");
-       gridType->add("32");
-       gridType->value(0);
-       gridType->callback(cb_changeType, (void*)this);
-
-       active = new gCheck (x+44, y+4, 12, 12);
-
-       gridType->value(G_Conf.actionEditorGridVal);
-       active->value(G_Conf.actionEditorGridOn);
-
-       end();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gGridTool::~gGridTool() {
-       G_Conf.actionEditorGridVal = gridType->value();
-       G_Conf.actionEditorGridOn  = active->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gGridTool::cb_changeType(Fl_Widget *w, void *p)  { ((gGridTool*)p)->__cb_changeType(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gGridTool::__cb_changeType() {
-       calc();
-       parent->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gGridTool::isOn() {
-       return active->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gGridTool::getValue() {
-       switch (gridType->value()) {
-               case 0: return 1;
-               case 1: return 2;
-               case 2: return 3;
-               case 3: return 4;
-               case 4: return 6;
-               case 5: return 8;
-               case 6: return 16;
-               case 7: return 32;
-       }
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gGridTool::calc() {
-
-       points.clear();
-       frames.clear();
-       bars.clear();
-       beats.clear();
-
-       /* find beats, bars and grid. The method is the same of the waveform in sample
-        * editor. Take totalwidth (the width in pixel of the area to draw), knowing
-        * that totalWidth = totalFrames / zoom. Then, for each pixel of totalwidth,
-        * put a concentrate of each block (which is totalFrames / zoom) */
-
-       int  j   = 0;
-       int fpgc = floor(G_Mixer.framesPerBeat / getValue());  // frames per grid cell
-
-       for (int i=1; i<parent->totalWidth; i++) {   // if i=0, step=0 -> useless cycle
-               int step = parent->zoom*i;
-               while (j < step && j < G_Mixer.totalFrames) {
-                       if (j % fpgc == 0) {
-                               points.add(i);
-                               frames.add(j);
-                       }
-                       if (j % G_Mixer.framesPerBeat == 0)
-                               beats.add(i);
-                       if (j % G_Mixer.framesPerBar == 0 && i != 1)
-                               bars.add(i);
-                       if (j == G_Mixer.totalFrames-1)
-                               parent->coverX = i;
-                       j++;
-               }
-               j = step;
-       }
-
-       /* fix coverX if == 0, which means G_Mixer.beats == 32 */
-
-       if (G_Mixer.beats == 32)
-               parent->coverX = parent->totalWidth;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gGridTool::getSnapPoint(int v) {
-
-       if (v == 0) return 0;
-
-       for (int i=0; i<(int)points.size; i++) {
-
-               if (i == (int) points.size-1)
-                       return points.at(i);
-
-               int gp  = points.at(i);
-               int gpn = points.at(i+1);
-
-               if (v >= gp && v < gpn)
-                       return gp;
-       }
-       return v;  // default value
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gGridTool::getSnapFrame(int v) {
-
-       v *= parent->zoom;  // transformation pixel -> frame
-
-       for (int i=0; i<(int)frames.size; i++) {
-
-               if (i == (int) frames.size-1)
-                       return frames.at(i);
-
-               int gf  = frames.at(i);     // grid frame
-               int gfn = frames.at(i+1);   // grid frame next
-
-               if (v >= gf && v < gfn) {
-
-                       /* which one is the closest? gf < v < gfn */
-
-                       if ((gfn - v) < (v - gf))
-                               return gfn;
-                       else
-                               return gf;
-               }
-       }
-       return v;  // default value
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gGridTool::getCellSize() {
-       return (parent->coverX - parent->ac->x()) / G_Mixer.beats / getValue();
-}
diff --git a/src/gd_actionEditor.h b/src/gd_actionEditor.h
deleted file mode 100644 (file)
index 71c37fd..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_actionEditor
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_ACTIONEDITOR_H
-#define GD_ACTIONEDITOR_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Scroll.H>
-#include "ge_window.h"
-
-
-/* gActionEditor
- * main window which contains the tools for dealing with actions.
- * This class calculates chan, zoom, frames per beat, and so on. Each
- * sub-widget contains a pointer to this window to query those data. */
-
-class gdActionEditor : public gWindow {
-
-private:
-
-       /* update
-        * compute total width, in pixel. */
-
-       void update();
-
-public:
-
-       gdActionEditor(class Channel *chan);
-       ~gdActionEditor();
-
-       int handle(int e);
-
-       int getActionType();
-
-       static void cb_zoomIn(Fl_Widget *w, void *p);
-       static void cb_zoomOut(Fl_Widget *w, void *p);
-       inline void __cb_zoomIn();
-       inline void __cb_zoomOut();
-
-       class gChoice   *actionType;
-       class gGridTool *gridTool;
-       class gClick    *zoomIn;
-       class gClick    *zoomOut;
-       class gScroll   *scroller;       // widget container
-
-       class gActionChannel      *ac;
-       class gMuteChannel        *mc;
-       class gEnvelopeChannel    *vc;
-       class gPianoRollContainer *pr;
-
-       gVector <class gActionWidget*> widgets;
-
-       class Channel *chan;
-
-       int zoom;
-       int totalWidth;  // total width of the widget, in pixel (zoom affected)
-       int coverX;              // x1 of the unused area (x2 = totalWidth)
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gGridTool : public Fl_Group {
-
-private:
-       class gChoice  *gridType;
-       class gCheck   *active;
-
-       class gdActionEditor *parent;
-
-       static void cb_changeType(Fl_Widget *w, void *p);
-       inline void __cb_changeType();
-
-public:
-
-       gGridTool(int x, int y, gdActionEditor *parent);
-       ~gGridTool();
-
-       int  getValue();
-       bool isOn();
-       void calc();
-
-       /* getSnapPoint
-        * given a cursor position in input, return the x coordinates of the
-        * nearest snap point (in pixel, clean, ie. not x()-shifted) */
-
-       int getSnapPoint(int v);
-       int getSnapFrame(int v);
-
-       /* getCellSize
-        * return the size in pixel of a single cell of the grid. */
-
-       int getCellSize();
-
-       gVector<int> points;   // points of the grid
-       gVector<int> frames;   // frames of the grid
-
-       gVector<int> bars;
-       gVector<int> beats;
-};
-
-
-#endif
diff --git a/src/gd_beatsInput.cpp b/src/gd_beatsInput.cpp
deleted file mode 100644 (file)
index 0c381c9..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_beatsInput
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_beatsInput.h"
-#include "gd_mainWindow.h"
-#include "gui_utils.h"
-#include "patch.h"
-#include "glue.h"
-#include "mixer.h"
-#include "conf.h"
-
-
-extern Mixer                            G_Mixer;
-extern Conf          G_Conf;
-extern gdMainWindow *mainWin;
-
-
-gdBeatsInput::gdBeatsInput()
-       : gWindow(164, 60, "Beats")
-{
-       if (G_Conf.beatsX)
-               resize(G_Conf.beatsX, G_Conf.beatsY, w(), h());
-
-       set_modal();
-
-       beats     = new gInput(8,  8,  35, 20);
-       bars      = new gInput(47, 8,  35, 20);
-       ok                  = new gClick(86, 8,  70, 20, "Ok");
-       resizeRec = new gCheck(8,  40, 12, 12, "resize recorded actions");
-       end();
-
-       char buf_bars[3]; sprintf(buf_bars, "%d", G_Mixer.bars);
-       char buf_beats[3]; sprintf(buf_beats, "%d", G_Mixer.beats);
-       beats->maximum_size(2);
-       beats->value(buf_beats);
-       beats->type(FL_INT_INPUT);
-       bars->maximum_size(2);
-       bars->value(buf_bars);
-       bars->type(FL_INT_INPUT);
-       ok->shortcut(FL_Enter);
-       ok->callback(cb_update_batt, (void*)this);
-       resizeRec->value(G_Conf.resizeRecordings);
-
-       gu_setFavicon(this);
-       setId(WID_BEATS);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdBeatsInput::~gdBeatsInput()
-{
-       G_Conf.beatsX = x();
-       G_Conf.beatsY = y();
-       G_Conf.resizeRecordings =       resizeRec->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBeatsInput::cb_update_batt(Fl_Widget *w, void *p) { ((gdBeatsInput*)p)->__cb_update_batt(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBeatsInput::__cb_update_batt()
-{
-       if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
-               return;
-       glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value());
-       do_callback();
-}
diff --git a/src/gd_beatsInput.h b/src/gd_beatsInput.h
deleted file mode 100644 (file)
index 8a5ccca..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_beatsInput
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GD_BEATSINPUT_H
-#define GD_BEATSINPUT_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "ge_window.h"
-
-
-class gdBeatsInput : public gWindow
-{
-private:
-
-       static void cb_update_batt(Fl_Widget *w, void *p);
-       inline void __cb_update_batt();
-
-       class gInput *beats;
-       class gInput *bars;
-       class gClick *ok;
-       class gCheck *resizeRec;
-
-public:
-
-       gdBeatsInput();
-       ~gdBeatsInput();
-};
-
-
-#endif
diff --git a/src/gd_bpmInput.cpp b/src/gd_bpmInput.cpp
deleted file mode 100644 (file)
index 048fe0a..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_bpmInput
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_bpmInput.h"
-#include "gd_mainWindow.h"
-#include "conf.h"
-#include "ge_mixed.h"
-#include "mixer.h"
-#include "gui_utils.h"
-#include "glue.h"
-
-
-extern Mixer                    G_Mixer;
-extern Conf          G_Conf;
-extern gdMainWindow *mainWin;
-
-
-gdBpmInput::gdBpmInput(const char *label)
-: gWindow(144, 36, "Bpm") {
-
-       if (G_Conf.bpmX)
-               resize(G_Conf.bpmX, G_Conf.bpmY, w(), h());
-
-       set_modal();
-
-       input_a = new gInput(8,  8, 30, 20);
-       input_b = new gInput(42, 8, 20, 20);
-       ok                = new gClick(66, 8, 70, 20, "Ok");
-       end();
-
-       char   a[4];
-       snprintf(a, 4, "%d", (int) G_Mixer.bpm);
-       char   b[2];
-       for (unsigned i=0; i<strlen(label); i++)        // looking for the dot
-               if (label[i] == '.') {
-                       snprintf(b, 2, "%c", label[i+1]);
-                       break;
-               }
-
-       input_a->maximum_size(3);
-       input_a->type(FL_INT_INPUT);
-       input_a->value(a);
-       input_b->maximum_size(1);
-       input_b->type(FL_INT_INPUT);
-       input_b->value(b);
-
-       ok->shortcut(FL_Enter);
-       ok->callback(cb_update_bpm, (void*)this);
-
-       gu_setFavicon(this);
-       setId(WID_BPM);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdBpmInput::~gdBpmInput() {
-       G_Conf.bpmX = x();
-       G_Conf.bpmY = y();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBpmInput::cb_update_bpm(Fl_Widget *w, void *p) { ((gdBpmInput*)p)->__cb_update_bpm(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBpmInput::__cb_update_bpm() {
-       if (strcmp(input_a->value(), "") == 0)
-               return;
-       glue_setBpm(input_a->value(), input_b->value());
-       do_callback();
-}
diff --git a/src/gd_bpmInput.h b/src/gd_bpmInput.h
deleted file mode 100644 (file)
index e3bc211..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_bpmInput
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GD_BPMINPUT_H
-#define GD_BPMINPUT_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "ge_window.h"
-
-
-class gdBpmInput : public gWindow {
-private:
-       static void cb_update_bpm(Fl_Widget *w, void *p);
-       inline void __cb_update_bpm();
-
-       class gInput *input_a;
-       class gInput *input_b;
-       class gClick *ok;
-
-public:
-       gdBpmInput(const char *label); // pointer to mainWin->timing->bpm->label()
-       ~gdBpmInput();
-};
-
-#endif
diff --git a/src/gd_browser.cpp b/src/gd_browser.cpp
deleted file mode 100644 (file)
index 188a6c0..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_browser
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gd_browser.h"
-#include "ge_browser.h"
-#include "gd_pluginList.h"
-#include "gd_mainWindow.h"
-#include "gg_keyboard.h"
-#include "gd_warnings.h"
-#include "ge_channel.h"
-#include "mixer.h"
-#include "graphics.h"
-#include "wave.h"
-#include "glue.h"
-#include "pluginHost.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "patch.h"
-#include "conf.h"
-
-
-extern Patch         G_Patch;
-extern Conf             G_Conf;
-extern Mixer         G_Mixer;
-#ifdef WITH_VST
-extern PluginHost    G_PluginHost;
-#endif
-extern gdMainWindow    *mainWin;
-
-
-gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int type, int stackType)
-       :       gWindow  (396, 302, title),
-               ch       (ch),
-               type     (type),
-               stackType(stackType)
-{
-       set_non_modal();
-
-       browser = new gBrowser(8, 36, 380, 230);
-       Fl_Group *group_btn = new Fl_Group(8, 274, 380, 20);
-               gBox *b = new gBox(8, 274, 204, 20);                                            // spacer window border <-> buttons
-               ok        = new gClick(308, 274, 80, 20);
-               cancel  = new gClick(220, 274, 80, 20, "Cancel");
-               status  = new gProgress(8, 274, 204, 20);
-               status->minimum(0);
-               status->maximum(1);
-               status->hide();   // show the bar only if necessary
-       group_btn->resizable(b);
-       group_btn->end();
-
-       Fl_Group *group_upd = new Fl_Group(8, 8, 380, 25);
-               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
-                       name = new gInput(208, 8, 152, 20);
-               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
-                       where = new gInput(8, 8, 192, 20);
-               else
-                       where = new gInput(8, 8, 352, 20);
-               updir   = new gClick(368, 8, 20, 20, "", updirOff_xpm, updirOn_xpm);
-       group_upd->resizable(where);
-       group_upd->end();
-
-       end();
-
-       resizable(browser);
-       size_range(w(), h(), 0, 0);
-
-       where->readonly(true);
-       where->cursor_color(COLOR_BG_DARK);
-
-       if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
-               ok->label("Save");
-       else
-               ok->label("Load");
-
-       if (type == BROWSER_LOAD_PATCH)
-               ok->callback(cb_load_patch, (void*)this);
-       else
-       if (type == BROWSER_LOAD_SAMPLE)
-               ok->callback(cb_load_sample, (void*)this);
-       else
-       if (type == BROWSER_SAVE_PATCH) {
-               ok->callback(cb_save_patch, (void*)this);
-               name->value(G_Patch.name[0] == '\0' ? "my_patch.gptc" : G_Patch.name);
-               name->maximum_size(MAX_PATCHNAME_LEN+5); // +5 for ".gptc"
-       }
-       else
-       if (type == BROWSER_SAVE_SAMPLE) {
-               ok->callback(cb_save_sample, (void*)this);
-               name->value(((SampleChannel*)ch)->wave->name.c_str());
-       }
-       else
-       if (type == BROWSER_SAVE_PROJECT) {
-               ok->callback(cb_save_project, (void*)this);
-               name->value(gStripExt(G_Patch.name).c_str());
-       }
-#ifdef WITH_VST
-       else
-       if (type == BROWSER_LOAD_PLUGIN) {
-               ok->callback(cb_loadPlugin, (void*)this);
-       }
-#endif
-
-       ok->shortcut(FL_Enter);
-
-       updir->callback(cb_up, (void*)this);
-       cancel->callback(cb_close, (void*)this);
-       browser->callback(cb_down, this);
-       browser->path_obj = where;
-       browser->init(initPath);
-
-       if (G_Conf.browserW)
-               resize(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH);
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdBrowser::~gdBrowser() {
-       G_Conf.browserX = x();
-       G_Conf.browserY = y();
-       G_Conf.browserW = w();
-       G_Conf.browserH = h();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::cb_load_patch  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_load_patch();  }
-void gdBrowser::cb_load_sample (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_load_sample(); }
-void gdBrowser::cb_save_sample (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_sample(); }
-void gdBrowser::cb_save_patch  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_patch(); }
-void gdBrowser::cb_save_project(Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_project(); }
-void gdBrowser::cb_down        (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_down(); }
-void gdBrowser::cb_up          (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_up(); }
-void gdBrowser::cb_close       (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_close(); }
-#ifdef WITH_VST
-void gdBrowser::cb_loadPlugin  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_loadPlugin(); }
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_load_patch() {
-
-       if (browser->text(browser->value()) == NULL)
-               return;
-
-       /* patchFile is the file to open.
-        * For patches:  browser->get_selected_item()
-        * for projects: browser->get_selected_item() without extention +
-        *               patch name appended */
-
-       std::string patchFile = browser->get_selected_item();;
-       bool        isProject;
-
-       if (gIsProject(browser->get_selected_item())) {
-               std::string patchName = gGetProjectName(browser->get_selected_item());
-#if defined(__linux__) || defined(__APPLE__)
-               patchFile = patchFile+"/"+patchName+".gptc";
-#elif defined(_WIN32)
-               patchFile = patchFile+"\\"+patchName+".gptc";
-#endif
-               isProject = true;
-       }
-       else
-               isProject = false;
-
-       int res = glue_loadPatch(patchFile.c_str(),     browser->path_obj->value(),     status, isProject);
-
-       if (res == PATCH_UNREADABLE) {
-               status->hide();
-               if (isProject)
-                       gdAlert("This project is unreadable.");
-               else
-                       gdAlert("This patch is unreadable.");
-       }
-       else if (res == PATCH_INVALID) {
-               status->hide();
-               if (isProject)
-                       gdAlert("This project is not valid.");
-               else
-                       gdAlert("This patch is not valid.");
-       }
-       else
-               do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_save_sample() {
-
-       if (strcmp(name->value(), "") == 0) {    /// FIXME glue business
-               gdAlert("Please choose a file name.");
-               return;
-       }
-
-       /* bruteforce check extension. */
-
-       std::string filename = gStripExt(name->value());
-       char fullpath[PATH_MAX];
-       sprintf(fullpath, "%s/%s.wav", where->value(), filename.c_str());
-
-       if (gFileExists(fullpath))
-               if (!gdConfirmWin("Warning", "File exists: overwrite?"))
-                       return;
-
-       if (((SampleChannel*)ch)->save(fullpath))
-               do_callback();
-       else
-               gdAlert("Unable to save this sample!");
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_load_sample() {
-       if (browser->text(browser->value()) == NULL)
-               return;
-
-       int res = glue_loadChannel((SampleChannel*) ch, browser->get_selected_item());
-
-       if (res == SAMPLE_LOADED_OK) {
-               do_callback();
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open
-       }
-       else
-               mainWin->keyboard->printChannelMessage(res);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_down() {
-       const char *path = browser->get_selected_item();
-       if (!path)  // when click on an empty area
-               return;
-       if (!gIsDir(path)) {
-
-               /* set the name of the patch/sample/project as the selected item */
-
-               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) {
-                       if (gIsProject(path)) {
-                               std::string tmp = browser->text(browser->value());
-                               tmp.erase(0, 4);
-                               name->value(tmp.c_str());
-                       }
-                       else
-                               name->value(browser->text(browser->value()));
-               }
-               return;
-       }
-       browser->clear();
-       browser->down_dir(path);
-       browser->sort();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_up() {
-       browser->clear();
-       browser->up_dir();
-       browser->sort();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_save_patch() {
-
-       if (strcmp(name->value(), "") == 0) {  /// FIXME glue business
-               gdAlert("Please choose a file name.");
-               return;
-       }
-
-       /* if name->value() contains ".gptc" */
-
-       char ext[6] = ".gptc";
-       if (strstr(name->value(), ".gptc") != NULL)
-               ext[0] = '\0';
-
-       char fullpath[PATH_MAX];
-       sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext);
-       if (gFileExists(fullpath))
-               if (!gdConfirmWin("Warning", "File exists: overwrite?"))
-                       return;
-
-       if (glue_savePatch(fullpath, name->value(), false)) // false == not a project
-               do_callback();
-       else
-               gdAlert("Unable to save the patch!");
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_save_project() {
-
-       if (strcmp(name->value(), "") == 0) {    /// FIXME glue business
-               gdAlert("Please choose a project name.");
-               return;
-       }
-
-       /* check if name->value() contains ".gprj" */
-
-       char ext[6] = ".gprj";
-       if (strstr(name->value(), ".gprj") != NULL)
-               ext[0] = '\0';
-
-       char fullpath[PATH_MAX];
-#if defined(_WIN32)
-       sprintf(fullpath, "%s\\%s%s", where->value(), name->value(), ext);
-#else
-       sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext);
-#endif
-
-       if (gIsProject(fullpath) && !gdConfirmWin("Warning", "Project exists: overwrite?"))
-               return;
-
-       if (glue_saveProject(fullpath, name->value()))
-               do_callback();
-       else
-               gdAlert("Unable to save the project!");
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-void gdBrowser::__cb_loadPlugin() {
-
-       if (browser->text(browser->value()) == NULL)
-               return;
-
-       int res = G_PluginHost.addPlugin(browser->get_selected_item(), stackType, ch);
-
-       /* store the folder path inside G_Conf, in order to reuse it the
-        * next time. */
-
-       G_Conf.setPath(G_Conf.pluginPath, where->value());
-
-       if (res)
-               do_callback();
-       else
-               gdAlert("Unable to load the selected plugin!");
-}
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBrowser::__cb_close() {
-       do_callback();
-}
diff --git a/src/gd_browser.h b/src/gd_browser.h
deleted file mode 100644 (file)
index 61f482d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_browser
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_BROWSER_H
-#define GD_BROWSER_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include "ge_window.h"
-
-
-/* TODO - this class must be subclassed into gdPluginBrowser, gdFileBrowser,
- * and so on. It's a real mess right now. */
-
-class gdBrowser : public gWindow {
-
-private:
-       static void cb_down(Fl_Widget *v, void *p);
-       static void cb_up  (Fl_Widget *v, void *p);
-       static void cb_load_sample (Fl_Widget *v, void *p);
-       static void cb_save_sample (Fl_Widget *v, void *p);
-       static void cb_load_patch  (Fl_Widget *v, void *p);
-       static void cb_save_patch  (Fl_Widget *v, void *p);
-       static void cb_save_project(Fl_Widget *v, void *p);
-       static void cb_close       (Fl_Widget *w, void *p);
-#ifdef WITH_VST
-       static void cb_loadPlugin  (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_down();
-       inline void __cb_up();
-       inline void __cb_load_sample();
-       inline void __cb_save_sample();
-       inline void __cb_save_project();
-       inline void __cb_load_patch();
-       inline void __cb_save_patch();
-       inline void __cb_close();
-#ifdef WITH_VST
-       inline void __cb_loadPlugin();
-#endif
-
-       class gBrowser  *browser;
-       class gClick    *ok;
-       class gClick    *cancel;
-       class gInput    *where;
-       class gInput    *name;
-       class gClick    *updir;
-       class gProgress *status;
-
-       class Channel *ch;
-
-       /* browser type: see const.h */
-
-       /** FIXME internal enum:
-        * enum browserType {
-                * TYPE_A,
-                * TYPE_B,
-                * ....
-                * }; */
-       int type;
-
-       /* PluginHost stack type. Used only when loading plugins */
-
-       int stackType;
-
-       char selectedFile[FILENAME_MAX];
-
-public:
-       gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0);
-       ~gdBrowser();
-
-       char* SelectedFile();
-};
-
-#endif
diff --git a/src/gd_config.cpp b/src/gd_config.cpp
deleted file mode 100644 (file)
index ab34fc6..0000000
+++ /dev/null
@@ -1,863 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_config
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gd_config.h"
-#include "gd_keyGrabber.h"
-#include "gd_devInfo.h"
-#include "gd_browser.h"
-#include "ge_mixed.h"
-#include "conf.h"
-#include "midiMapConf.h"
-#include "log.h"
-#include "gui_utils.h"
-#include "patch.h"
-#include "kernelAudio.h"
-#include "kernelMidi.h"
-
-
-extern Patch G_Patch;
-extern Conf     G_Conf;
-extern bool  G_audio_status;
-extern MidiMapConf G_MidiMap;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gTabMisc::gTabMisc(int X, int Y, int W, int H)
-       : Fl_Group(X, Y, W, H, "Misc")
-{
-       begin();
-       debugMsg = new gChoice(x()+92,  y()+9,  253, 20, "Debug messages");
-       end();
-
-       debugMsg->add("(disabled)");
-       debugMsg->add("To standard output");
-       debugMsg->add("To file");
-
-       labelsize(11);
-
-       switch (G_Conf.logMode) {
-               case LOG_MODE_MUTE:
-                       debugMsg->value(0);
-                       break;
-               case LOG_MODE_STDOUT:
-                       debugMsg->value(1);
-                       break;
-               case LOG_MODE_FILE:
-                       debugMsg->value(2);
-                       break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMisc::save()
-{
-       switch(debugMsg->value()) {
-               case 0:
-                       G_Conf.logMode = LOG_MODE_MUTE;
-                       break;
-               case 1:
-                       G_Conf.logMode = LOG_MODE_STDOUT;
-                       break;
-               case 2:
-                       G_Conf.logMode = LOG_MODE_FILE;
-                       break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gTabAudio::gTabAudio(int X, int Y, int W, int H)
-       : Fl_Group(X, Y, W, H, "Sound System")
-{
-       begin();
-       soundsys    = new gChoice(x()+92,  y()+9,  253, 20, "System");
-       buffersize  = new gChoice(x()+92,  y()+37, 55,  20, "Buffer size");
-       samplerate  = new gChoice(x()+290, y()+37, 55,  20, "Sample rate");
-       sounddevOut = new gChoice(x()+92,  y()+65, 225, 20, "Output device");
-       devOutInfo  = new gClick (x()+325, y()+65, 20,  20, "?");
-       channelsOut = new gChoice(x()+92,  y()+93, 55,  20, "Output channels");
-       limitOutput = new gCheck (x()+155, y()+97, 55,  20, "Limit output");
-       sounddevIn  = new gChoice(x()+92,  y()+121, 225, 20, "Input device");
-       devInInfo   = new gClick (x()+325, y()+121, 20,  20, "?");
-       channelsIn  = new gChoice(x()+92,  y()+149, 55,  20, "Input channels");
-       delayComp   = new gInput (x()+290, y()+149, 55,  20, "Rec delay comp.");
-       rsmpQuality = new gChoice(x()+92, y()+177, 253, 20, "Resampling");
-                new gBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92, "Restart Giada for the changes to take effect.");
-       end();
-       labelsize(11);
-
-#if defined(__linux__)
-
-       if (kernelAudio::hasAPI(RtAudio::LINUX_ALSA))
-               soundsys->add("ALSA");
-       if (kernelAudio::hasAPI(RtAudio::UNIX_JACK))
-               soundsys->add("Jack");
-       if (kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
-               soundsys->add("PulseAudio");
-
-       switch (G_Conf.soundSystem) {
-               case SYS_API_ALSA:
-                       soundsys->show("ALSA");
-                       break;
-               case SYS_API_JACK:
-                       soundsys->show("Jack");
-                       buffersize->deactivate();
-                       samplerate->deactivate();
-                       break;
-               case SYS_API_PULSE:
-                       soundsys->show("PulseAudio");
-                       break;
-       }
-       soundsysInitValue = soundsys->value();
-
-#elif defined(_WIN32)
-
-       if (kernelAudio::hasAPI(RtAudio::WINDOWS_DS))
-               soundsys->add("DirectSound");
-       if (kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO))
-               soundsys->add("ASIO");
-       soundsys->show(G_Conf.soundSystem == SYS_API_DS ? "DirectSound" : "ASIO");
-       soundsysInitValue = soundsys->value();
-
-#elif defined (__APPLE__)
-
-       if (kernelAudio::hasAPI(RtAudio::MACOSX_CORE))
-               soundsys->add("CoreAudio");
-       soundsys->show("CoreAudio");
-       soundsysInitValue = soundsys->value();
-
-#endif
-
-       sounddevIn->callback(cb_fetchInChans, this);
-       sounddevOut->callback(cb_fetchOutChans, this);
-
-       devOutInfo->callback(cb_showOutputInfo, this);
-       devInInfo->callback(cb_showInputInfo, this);
-
-       fetchSoundDevs();
-
-       fetchOutChans(sounddevOut->value());
-       fetchInChans(sounddevIn->value());
-
-       buffersize->add("8");
-       buffersize->add("16");
-       buffersize->add("32");
-       buffersize->add("64");
-       buffersize->add("128");
-       buffersize->add("256");
-       buffersize->add("512");
-       buffersize->add("1024");
-       buffersize->add("2048");
-       buffersize->add("4096");
-
-       char buf[8];
-       sprintf(buf, "%d", G_Conf.buffersize);
-       buffersize->show(buf);
-
-       /* fill frequency dropdown menu */
-
-       int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value());
-       for (int i=0; i<nfreq; i++) {
-               char buf[16];
-               int  freq = kernelAudio::getFreq(sounddevOut->value(), i);
-               sprintf(buf, "%d", freq);
-               samplerate->add(buf);
-               if (freq == G_Conf.samplerate)
-                       samplerate->value(i);
-       }
-
-       rsmpQuality->add("Sinc best quality (very slow)");
-       rsmpQuality->add("Sinc medium quality (slow)");
-       rsmpQuality->add("Sinc basic quality (medium)");
-       rsmpQuality->add("Zero Order Hold (fast)");
-       rsmpQuality->add("Linear (very fast)");
-       rsmpQuality->value(G_Conf.rsmpQuality);
-
-       buf[0] = '\0';
-       sprintf(buf, "%d", G_Conf.delayComp);
-       delayComp->value(buf);
-       delayComp->type(FL_INT_INPUT);
-       delayComp->maximum_size(5);
-
-       limitOutput->value(G_Conf.limitOutput);
-       soundsys->callback(cb_deactivate_sounddev, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_deactivate_sounddev(); }
-void gTabAudio::cb_fetchInChans(Fl_Widget *w, void *p)        { ((gTabAudio*)p)->__cb_fetchInChans(); }
-void gTabAudio::cb_fetchOutChans(Fl_Widget *w, void *p)       { ((gTabAudio*)p)->__cb_fetchOutChans(); }
-void gTabAudio::cb_showInputInfo(Fl_Widget *w, void *p)       { ((gTabAudio*)p)->__cb_showInputInfo(); }
-void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p)      { ((gTabAudio*)p)->__cb_showOutputInfo(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::__cb_fetchInChans()
-{
-       fetchInChans(sounddevIn->value());
-       channelsIn->value(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::__cb_fetchOutChans()
-{
-       fetchOutChans(sounddevOut->value());
-       channelsOut->value(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::__cb_showInputInfo()
-{
-       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       new gdDevInfo(dev);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::__cb_showOutputInfo()
-{
-       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       new gdDevInfo(dev);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::__cb_deactivate_sounddev()
-{
-       /* if the user changes sound system (eg ALSA->JACK) device menu deactivates.
-        * If it returns to the original sound system, we re-fill the list by
-        * querying kernelAudio. */
-
-       if (soundsysInitValue == soundsys->value()) {
-               sounddevOut->clear();
-               sounddevIn->clear();
-
-               fetchSoundDevs();
-
-               /* the '?' button is added by fetchSoundDevs */
-
-               fetchOutChans(sounddevOut->value());
-               sounddevOut->activate();
-               channelsOut->activate();
-
-               /* chan menus and '?' button are activated by fetchInChans(...) */
-
-               fetchInChans(sounddevIn->value());
-               sounddevIn->activate();
-       }
-       else {
-               sounddevOut->deactivate();
-               sounddevOut->clear();
-               sounddevOut->add("-- restart to fetch device(s) --");
-               sounddevOut->value(0);
-               channelsOut->deactivate();
-               devOutInfo->deactivate();
-
-               sounddevIn->deactivate();
-               sounddevIn->clear();
-               sounddevIn->add("-- restart to fetch device(s) --");
-               sounddevIn->value(0);
-               channelsIn->deactivate();
-               devInInfo->deactivate();
-       }
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::fetchInChans(int menuItem)
-{
-       /* if menuItem==0 device in input is disabled. */
-
-       if (menuItem == 0) {
-               devInInfo ->deactivate();
-               channelsIn->deactivate();
-               delayComp ->deactivate();
-               return;
-       }
-
-       devInInfo ->activate();
-       channelsIn->activate();
-       delayComp ->activate();
-
-       channelsIn->clear();
-
-       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       unsigned chs = kernelAudio::getMaxInChans(dev);
-
-       if (chs == 0) {
-               channelsIn->add("none");
-               channelsIn->value(0);
-               return;
-       }
-       for (unsigned i=0; i<chs; i+=2) {
-               char str[16];
-               sprintf(str, "%d-%d", (i+1), (i+2));
-               channelsIn->add(str);
-       }
-       channelsIn->value(G_Conf.channelsIn);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::fetchOutChans(int menuItem)
-{
-       channelsOut->clear();
-
-       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       unsigned chs = kernelAudio::getMaxOutChans(dev);
-
-       if (chs == 0) {
-               channelsOut->add("none");
-               channelsOut->value(0);
-               return;
-       }
-       for (unsigned i=0; i<chs; i+=2) {
-               char str[16];
-               sprintf(str, "%d-%d", (i+1), (i+2));
-               channelsOut->add(str);
-       }
-       channelsOut->value(G_Conf.channelsOut);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gTabAudio::findMenuDevice(gChoice *m, int device)
-{
-       if (device == -1)
-               return 0;
-
-       if (G_audio_status == false)
-               return 0;
-
-       for (int i=0; i<m->size(); i++) {
-               if (kernelAudio::getDeviceName(device) == NULL)
-                       continue;
-               if (m->text(i) == NULL)
-                       continue;
-               if (strcmp(m->text(i), kernelAudio::getDeviceName(device))==0)
-                       return i;
-       }
-
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::fetchSoundDevs()
-{
-       if (kernelAudio::numDevs == 0) {
-               sounddevOut->add("-- no devices found --");
-               sounddevOut->value(0);
-               sounddevIn->add("-- no devices found --");
-               sounddevIn->value(0);
-               devInInfo ->deactivate();
-               devOutInfo->deactivate();
-       }
-       else {
-
-               devInInfo ->activate();
-               devOutInfo->activate();
-
-               /* input device may be disabled: now device number -1 is the disabled
-                * one. KernelAudio knows how to handle it. */
-
-               sounddevIn->add("(disabled)");
-
-               for (unsigned i=0; i<kernelAudio::numDevs; i++) {
-
-                       /* escaping '/', very dangerous in FLTK (it creates a submenu) */
-
-                       std::string tmp = kernelAudio::getDeviceName(i);
-                       for (unsigned k=0; k<tmp.size(); k++)
-                               if (tmp[k] == '/' || tmp[k] == '|' || tmp[k] == '&' || tmp[k] == '_')
-                                       tmp[k] = '-';
-
-                       /* add to list devices with at least 1 channel available. In this
-                        * way we can filter devices only for input or output, e.g. an input
-                        * devices has 0 output channels. */
-
-                       if (kernelAudio::getMaxOutChans(i) > 0)
-                               sounddevOut->add(tmp.c_str());
-
-                       if (kernelAudio::getMaxInChans(i) > 0)
-                               sounddevIn->add(tmp.c_str());
-               }
-
-               /* we show the device saved in the configuration file. */
-
-               if (sounddevOut->size() == 0) {
-                       sounddevOut->add("-- no devices found --");
-                       sounddevOut->value(0);
-                       devOutInfo->deactivate();
-               }
-               else {
-                       int outMenuValue = findMenuDevice(sounddevOut, G_Conf.soundDeviceOut);
-                       sounddevOut->value(outMenuValue);
-               }
-
-               if (sounddevIn->size() == 0) {
-                       sounddevIn->add("-- no devices found --");
-                       sounddevIn->value(0);
-                       devInInfo->deactivate();
-               }
-               else {
-                       int inMenuValue = findMenuDevice(sounddevIn, G_Conf.soundDeviceIn);
-                       sounddevIn->value(inMenuValue);
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabAudio::save()
-{
-       /** FIXME - wrong, if API is missing! Right way in gTabMidi::save */
-
-#ifdef __linux__
-       if      (soundsys->value() == 0)        G_Conf.soundSystem = SYS_API_ALSA;
-       else if (soundsys->value() == 1)        G_Conf.soundSystem = SYS_API_JACK;
-       else if (soundsys->value() == 2)        G_Conf.soundSystem = SYS_API_PULSE;
-#else
-#ifdef _WIN32
-       if                      (soundsys->value() == 0)        G_Conf.soundSystem = SYS_API_DS;
-       else if (soundsys->value() == 1)  G_Conf.soundSystem = SYS_API_ASIO;
-#endif
-#endif
-
-       /* use the device name to search into the drop down menu's */
-
-       G_Conf.soundDeviceOut = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       G_Conf.soundDeviceIn  = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       G_Conf.channelsOut    = channelsOut->value();
-       G_Conf.channelsIn     = channelsIn->value();
-       G_Conf.limitOutput    = limitOutput->value();
-       G_Conf.rsmpQuality    = rsmpQuality->value();
-
-       /* if sounddevOut is disabled (because of system change e.g. alsa ->
-        * jack) its value is equal to -1. Change it! */
-
-       if (G_Conf.soundDeviceOut == -1)
-               G_Conf.soundDeviceOut = 0;
-
-       int bufsize = atoi(buffersize->text());
-       if (bufsize % 2 != 0) bufsize++;
-       if (bufsize < 8)                  bufsize = 8;
-       if (bufsize > 8192)             bufsize = 8192;
-       G_Conf.buffersize = bufsize;
-
-       const Fl_Menu_Item *i = NULL;
-       i = samplerate->mvalue(); // mvalue() returns a pointer to the last menu item that was picked
-       if (i)
-               G_Conf.samplerate = atoi(i->label());
-
-       int _delayComp = atoi(delayComp->value());
-       if (_delayComp < 0) _delayComp = 0;
-       G_Conf.delayComp = _delayComp;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gTabMidi::gTabMidi(int X, int Y, int W, int H)
-       : Fl_Group(X, Y, W, H, "MIDI")
-{
-       begin();
-       system    = new gChoice(x()+92, y()+9, 253, 20, "System");
-       portOut   = new gChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port");
-       portIn    = new gChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port");
-       noNoteOff = new gCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff");
-       midiMap   = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map");
-       sync        = new gChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync");
-       new gBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect.");
-       end();
-
-       labelsize(11);
-
-       system->callback(cb_changeSystem, (void*)this);
-
-       fetchSystems();
-       fetchOutPorts();
-       fetchInPorts();
-       fetchMidiMaps();
-
-       noNoteOff->value(G_Conf.noNoteOff);
-
-       sync->add("(disabled)");
-       sync->add("MIDI Clock (master)");
-       sync->add("MTC (master)");
-       if      (G_Conf.midiSync == MIDI_SYNC_NONE)
-               sync->value(0);
-       else if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
-               sync->value(1);
-       else if (G_Conf.midiSync == MIDI_SYNC_MTC_M)
-               sync->value(2);
-
-       systemInitValue = system->value();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::fetchOutPorts() {
-
-       if (kernelMidi::numOutPorts == 0) {
-               portOut->add("-- no ports found --");
-               portOut->value(0);
-               portOut->deactivate();
-       }
-       else {
-
-               portOut->add("(disabled)");
-
-               for (unsigned i=0; i<kernelMidi::numOutPorts; i++) {
-                       char *t = (char*) kernelMidi::getOutPortName(i);
-                       for (int k=0; t[k] != '\0'; k++)
-                               if (t[k] == '/' || t[k] == '|' || t[k] == '&' || t[k] == '_')
-                                       t[k] = '-';
-                       portOut->add(t);
-               }
-
-               portOut->value(G_Conf.midiPortOut+1);    // +1 because midiPortOut=-1 is '(disabled)'
-       }
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::fetchInPorts()
-{
-       if (kernelMidi::numInPorts == 0) {
-               portIn->add("-- no ports found --");
-               portIn->value(0);
-               portIn->deactivate();
-       }
-       else {
-
-               portIn->add("(disabled)");
-
-               for (unsigned i=0; i<kernelMidi::numInPorts; i++) {
-                       char *t = (char*) kernelMidi::getInPortName(i);
-                       for (int k=0; t[k] != '\0'; k++)
-                               if (t[k] == '/' || t[k] == '|' || t[k] == '&' || t[k] == '_')
-                                       t[k] = '-';
-                       portIn->add(t);
-               }
-
-               portIn->value(G_Conf.midiPortIn+1);    // +1 because midiPortIn=-1 is '(disabled)'
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::fetchMidiMaps()
-{
-       if (G_MidiMap.maps.size == 0) {
-               midiMap->add("(no MIDI maps available)");
-               midiMap->value(0);
-               midiMap->deactivate();
-               return;
-       }
-       for (unsigned i=0; i<G_MidiMap.maps.size; i++) {
-               const char *imap = G_MidiMap.maps.at(i).c_str();
-               midiMap->add(imap);
-               if (strcmp(G_Conf.midiMapPath, imap) == 0)
-                       midiMap->value(i);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::save()
-{
-       if      (!strcmp("ALSA", system->text(system->value())))
-               G_Conf.midiSystem = RtMidi::LINUX_ALSA;
-       else if (!strcmp("Jack", system->text(system->value())))
-               G_Conf.midiSystem = RtMidi::UNIX_JACK;
-       else if (!strcmp("Multimedia MIDI", system->text(system->value())))
-               G_Conf.midiSystem = RtMidi::WINDOWS_MM;
-       else if (!strcmp("OSX Core MIDI", system->text(system->value())))
-               G_Conf.midiSystem = RtMidi::MACOSX_CORE;
-
-       G_Conf.midiPortOut = portOut->value()-1;   // -1 because midiPortOut=-1 is '(disabled)'
-       G_Conf.midiPortIn  = portIn->value()-1;    // -1 because midiPortIn=-1 is '(disabled)'
-
-       G_Conf.noNoteOff   = noNoteOff->value();
-
-       G_Conf.setPath(G_Conf.midiMapPath, midiMap->text(midiMap->value()));
-
-       if      (sync->value() == 0)
-               G_Conf.midiSync = MIDI_SYNC_NONE;
-       else if (sync->value() == 1)
-               G_Conf.midiSync = MIDI_SYNC_CLOCK_M;
-       else if (sync->value() == 2)
-               G_Conf.midiSync = MIDI_SYNC_MTC_M;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::fetchSystems()
-{
-#if defined(__linux__)
-
-       if (kernelMidi::hasAPI(RtMidi::LINUX_ALSA))
-               system->add("ALSA");
-       if (kernelMidi::hasAPI(RtMidi::UNIX_JACK))
-               system->add("Jack");
-
-#elif defined(_WIN32)
-
-       if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM))
-               system->add("Multimedia MIDI");
-
-#elif defined (__APPLE__)
-
-       system->add("OSX Core MIDI");
-
-#endif
-
-       switch (G_Conf.midiSystem) {
-               case RtMidi::LINUX_ALSA:  system->show("ALSA"); break;
-               case RtMidi::UNIX_JACK:   system->show("Jack"); break;
-               case RtMidi::WINDOWS_MM:  system->show("Multimedia MIDI"); break;
-               case RtMidi::MACOSX_CORE: system->show("OSX Core MIDI"); break;
-               default: system->value(0); break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((gTabMidi*)p)->__cb_changeSystem(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabMidi::__cb_changeSystem()
-{
-       /* if the user changes MIDI device (eg ALSA->JACK) device menu deactivates.
-        * If it returns to the original system, we re-fill the list by
-        * querying kernelMidi. */
-
-       if (systemInitValue == system->value()) {
-               portOut->clear();
-               fetchOutPorts();
-               portOut->activate();
-       }
-       else {
-               portOut->deactivate();
-               portOut->clear();
-               portOut->add("-- restart to fetch device(s) --");
-               portOut->value(0);
-       }
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H)
-       : Fl_Group(X, Y, W, H, "Behaviors")
-{
-       begin();
-       Fl_Group *radioGrp_1 = new Fl_Group(x(), y()+10, w(), 70); // radio group for the mutex
-               new gBox(x(), y()+10, 70, 25, "When a channel with recorded actions is halted:", FL_ALIGN_LEFT);
-               recsStopOnChanHalt_1 = new gRadio(x()+25, y()+35, 280, 20, "stop it immediately");
-               recsStopOnChanHalt_0 = new gRadio(x()+25, y()+55, 280, 20, "play it until finished");
-       radioGrp_1->end();
-
-       Fl_Group *radioGrp_2 = new Fl_Group(x(), y()+70, w(), 70); // radio group for the mutex
-               new gBox(x(), y()+80, 70, 25, "When the sequencer is halted:", FL_ALIGN_LEFT);
-               chansStopOnSeqHalt_1 = new gRadio(x()+25, y()+105, 280, 20, "stop immediately all dynamic channels");
-               chansStopOnSeqHalt_0 = new gRadio(x()+25, y()+125, 280, 20, "play all dynamic channels until finished");
-       radioGrp_2->end();
-
-       treatRecsAsLoops  = new gCheck(x(), y()+155, 280, 20, "Treat one shot channels with actions as loops");
-
-       end();
-       labelsize(11);
-
-       G_Conf.recsStopOnChanHalt == 1 ? recsStopOnChanHalt_1->value(1) : recsStopOnChanHalt_0->value(1);
-       G_Conf.chansStopOnSeqHalt == 1 ? chansStopOnSeqHalt_1->value(1) : chansStopOnSeqHalt_0->value(1);
-       G_Conf.treatRecsAsLoops   == 1 ? treatRecsAsLoops->value(1)  : treatRecsAsLoops->value(0);
-
-       recsStopOnChanHalt_1->callback(cb_radio_mutex, (void*)this);
-       recsStopOnChanHalt_0->callback(cb_radio_mutex, (void*)this);
-       chansStopOnSeqHalt_1->callback(cb_radio_mutex, (void*)this);
-       chansStopOnSeqHalt_0->callback(cb_radio_mutex, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabBehaviors::cb_radio_mutex(Fl_Widget *w, void *p) { ((gTabBehaviors*)p)->__cb_radio_mutex(w); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w)
-{
-       ((Fl_Button *)w)->type(FL_RADIO_BUTTON);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gTabBehaviors::save()
-{
-       G_Conf.recsStopOnChanHalt = recsStopOnChanHalt_1->value() == 1 ? 1 : 0;
-       G_Conf.chansStopOnSeqHalt = chansStopOnSeqHalt_1->value() == 1 ? 1 : 0;
-       G_Conf.treatRecsAsLoops   = treatRecsAsLoops->value() == 1 ? 1 : 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration")
-{
-       set_modal();
-
-       if (G_Conf.configX)
-               resize(G_Conf.configX, G_Conf.configY, this->w(), this->h());
-
-       Fl_Tabs *tabs = new Fl_Tabs(8, 8, w-16, h-44);
-               tabAudio     = new gTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabMidi      = new gTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabBehaviors = new gTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabMisc      = new gTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-       tabs->end();
-
-       save     = new gClick (w-88, h-28, 80, 20, "Save");
-       cancel = new gClick (w-176, h-28, 80, 20, "Cancel");
-
-       end();
-
-       tabs->box(FL_FLAT_BOX); // TODO - G_BOX crashes FLTK 1.3.3
-
-       tabs->labelcolor(COLOR_TEXT_0);
-
-       save->callback(cb_save_config, (void*)this);
-       cancel->callback(cb_cancel, (void*)this);
-
-       gu_setFavicon(this);
-       setId(WID_CONFIG);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdConfig::~gdConfig()
-{
-       G_Conf.configX = x();
-       G_Conf.configY = y();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::cb_save_config(Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_save_config(); }
-void gdConfig::cb_cancel     (Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_cancel(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::__cb_save_config()
-{
-       tabAudio->save();
-       tabBehaviors->save();
-       tabMidi->save();
-       tabMisc->save();
-       do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::__cb_cancel()
-{
-       do_callback();
-}
diff --git a/src/gd_config.h b/src/gd_config.h
deleted file mode 100644 (file)
index fa28b80..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_config
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GD_CONFIG_H
-#define GD_CONFIG_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Tabs.H>
-#include "ge_window.h"
-
-
-class gdConfig : public gWindow
-{
-private:
-       static void cb_save_config        (Fl_Widget *w, void *p);
-       static void cb_cancel             (Fl_Widget *w, void *p);
-       inline void __cb_save_config();
-       inline void __cb_cancel();
-
-public:
-       gdConfig(int w, int h);
-       ~gdConfig();
-
-       class gTabAudio     *tabAudio;
-       class gTabBehaviors *tabBehaviors;
-       class gTabMidi      *tabMidi;
-       class gTabMisc      *tabMisc;
-       class gClick          *save;
-       class gClick          *cancel;
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gTabMidi : public Fl_Group
-{
-private:
-
-       void fetchSystems();
-       void fetchOutPorts();
-       void fetchInPorts();
-       void fetchMidiMaps();
-
-       static void cb_changeSystem  (Fl_Widget *w, void *p);
-       inline void __cb_changeSystem();
-
-       int systemInitValue;
-
-public:
-       
-       class gChoice *system;
-       class gChoice *portOut;
-       class gChoice *portIn;
-       class gCheck  *noNoteOff;
-       class gChoice *midiMap;
-       class gChoice *sync;
-
-       gTabMidi(int x, int y, int w, int h);
-
-       void save();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gTabAudio : public Fl_Group
-{
-private:
-       static void cb_deactivate_sounddev(Fl_Widget *w, void *p);
-       static void cb_fetchInChans       (Fl_Widget *w, void *p);
-       static void cb_fetchOutChans      (Fl_Widget *w, void *p);
-       static void cb_showInputInfo      (Fl_Widget *w, void *p);
-       static void cb_showOutputInfo     (Fl_Widget *w, void *p);
-       inline void __cb_deactivate_sounddev();
-       inline void __cb_fetchInChans();
-       inline void __cb_fetchOutChans();
-       inline void __cb_showInputInfo();
-       inline void __cb_showOutputInfo();
-
-       void fetchSoundDevs();
-       void fetchInChans(int menuItem);
-       void fetchOutChans(int menuItem);
-       int  findMenuDevice(class gChoice *m, int device);
-
-       int soundsysInitValue;
-
-public:
-       class gChoice *soundsys;
-       class gChoice *samplerate;
-       class gChoice *rsmpQuality;
-       class gChoice *sounddevIn;
-       class gClick  *devInInfo;
-       class gChoice *channelsIn;
-       class gChoice *sounddevOut;
-       class gClick  *devOutInfo;
-       class gChoice *channelsOut;
-       class gCheck  *limitOutput;
-       class gChoice *buffersize;
-       class gInput  *delayComp;
-
-       gTabAudio(int x, int y, int w, int h);
-
-       void save();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gTabBehaviors : public Fl_Group
-{
-private:
-       static void cb_radio_mutex  (Fl_Widget *w, void *p);
-       inline void __cb_radio_mutex(Fl_Widget *w);
-
-public:
-       class gRadio *recsStopOnChanHalt_1;
-       class gRadio *recsStopOnChanHalt_0;
-       class gRadio *chansStopOnSeqHalt_1;
-       class gRadio *chansStopOnSeqHalt_0;
-       class gCheck *treatRecsAsLoops;
-
-       gTabBehaviors(int x, int y, int w, int h);
-
-       void save();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gTabMisc : public Fl_Group
-{
-public:
-       class gChoice *debugMsg;
-
-       gTabMisc(int x, int y, int w, int h);
-
-       void save();
-};
-
-
-#endif
diff --git a/src/gd_devInfo.cpp b/src/gd_devInfo.cpp
deleted file mode 100644 (file)
index b7c5e40..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_devInfo
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_devInfo.h"
-#include "ge_mixed.h"
-#include "kernelAudio.h"
-#include "gui_utils.h"
-
-
-gdDevInfo::gdDevInfo(unsigned dev)
-: Fl_Window(340, 300, "Device information") {
-       set_modal();
-
-       text  = new gBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-       close = new gClick(252, h()-28, 80, 20, "Close");
-       end();
-
-       std::string bufTxt;
-       char bufNum[128];
-       int  lines = 0;
-
-       bufTxt  = "Device name: ";
-       bufTxt += +kernelAudio::getDeviceName(dev);
-       bufTxt += "\n";
-       lines++;
-
-       bufTxt += "Total output(s): ";
-       sprintf(bufNum, "%d\n", kernelAudio::getMaxOutChans(dev));
-       bufTxt += bufNum;
-       lines++;
-
-       bufTxt += "Total intput(s): ";
-       sprintf(bufNum, "%d\n", kernelAudio::getMaxInChans(dev));
-       bufTxt += bufNum;
-       lines++;
-
-       bufTxt += "Duplex channel(s): ";
-       sprintf(bufNum, "%d\n", kernelAudio::getDuplexChans(dev));
-       bufTxt += bufNum;
-       lines++;
-
-       bufTxt += "Default output: ";
-       sprintf(bufNum, "%s\n", kernelAudio::isDefaultOut(dev) ? "yes" : "no");
-       bufTxt += bufNum;
-       lines++;
-
-       bufTxt += "Default input: ";
-       sprintf(bufNum, "%s\n", kernelAudio::isDefaultIn(dev) ? "yes" : "no");
-       bufTxt += bufNum;
-       lines++;
-
-       int totalFreq = kernelAudio::getTotalFreqs(dev);
-       bufTxt += "Supported frequencies: ";
-       sprintf(bufNum, "%d", totalFreq);
-       bufTxt += bufNum;
-       lines++;
-
-       for (int i=0; i<totalFreq; i++) {
-               sprintf(bufNum, "%d  ", kernelAudio::getFreq(dev, i));
-               if (i%6 == 0) {    // new line each X printed freqs AND on the first line (i%0 != 0)
-                       bufTxt += "\n    ";
-                       lines++;
-               }
-               bufTxt += bufNum;
-       }
-
-       text->copy_label(bufTxt.c_str());
-
-       /* resize the window to fit the content. fl_height() returns the height
-        * of a line. fl_height() * total lines + margins + button size */
-
-       resize(x(), y(), w(), lines*fl_height() + 8 + 8 + 8 + 20);
-       close->position(close->x(), lines*fl_height() + 8 + 8);
-
-       close->callback(__cb_window_closer, (void*)this);
-       gu_setFavicon(this);
-       show();
-}
-
-
-gdDevInfo::~gdDevInfo() {}
diff --git a/src/gd_devInfo.h b/src/gd_devInfo.h
deleted file mode 100644 (file)
index c5a06ca..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_devInfo
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_DEV_INFO_H
-#define GD_DEV_INFO_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-
-
-class gdDevInfo : public Fl_Window {
-private:
-       class gBox       *text;
-       class gClick *close;
-
-public:
-       gdDevInfo(unsigned dev);
-       ~gdDevInfo();
-};
-
-#endif
diff --git a/src/gd_editor.cpp b/src/gd_editor.cpp
deleted file mode 100644 (file)
index 3e96a1b..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_editor
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_editor.h"
-#include "gd_mainWindow.h"
-#include "ge_waveform.h"
-#include "gd_warnings.h"
-#include "gg_waveTools.h"
-#include "ge_mixed.h"
-#include "gg_keyboard.h"
-#include "ge_channel.h"
-#include "waveFx.h"
-#include "conf.h"
-#include "graphics.h"
-#include "gui_utils.h"
-#include "glue.h"
-#include "mixerHandler.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "mixer.h"
-#include "wave.h"
-
-
-extern Mixer         G_Mixer;
-extern gdMainWindow *mainWin;
-extern Conf          G_Conf;
-
-
-gdEditor::gdEditor(SampleChannel *ch)
-  : gWindow(640, 480),
-    ch(ch)
-{
-  set_non_modal();
-
-  if (G_Conf.sampleEditorX)
-    resize(G_Conf.sampleEditorX, G_Conf.sampleEditorY, G_Conf.sampleEditorW, G_Conf.sampleEditorH);
-
-  /* top bar: grid and zoom tools */
-
-  Fl_Group *bar = new Fl_Group(8, 8, w()-16, 20);
-  bar->begin();
-    grid    = new gChoice(bar->x(), bar->y(), 50, 20);
-    snap    = new gCheck(grid->x()+grid->w()+4, bar->y()+4, 12, 12);
-    zoomOut = new gClick(bar->x()+bar->w()-20, bar->y(), 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
-    zoomIn  = new gClick(zoomOut->x()-24, bar->y(), 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
-  bar->end();
-  bar->resizable(new gBox(grid->x()+grid->w()+4, bar->y(), 80, bar->h()));
-
-  /* waveform */
-
-  waveTools = new gWaveTools(8, 36, w()-16, h()-120, ch);
-  waveTools->end();
-
-  /* other tools */
-
-  Fl_Group *tools = new Fl_Group(8, waveTools->y()+waveTools->h()+8, w()-16, 130);
-  tools->begin();
-    volume        = new gDial (tools->x()+42,                    tools->y(), 20, 20, "Volume");
-    volumeNum     = new gInput(volume->x()+volume->w()+4,        tools->y(), 46, 20, "dB");
-
-    boost         = new gDial (volumeNum->x()+volumeNum->w()+80, tools->y(), 20, 20, "Boost");
-    boostNum      = new gInput(boost->x()+boost->w()+4,          tools->y(), 46, 20, "dB");
-
-    normalize     = new gClick(boostNum->x()+boostNum->w()+54,   tools->y(), 70, 20, "Normalize");
-    pan           = new gDial (normalize->x()+normalize->w()+40, tools->y(), 20, 20, "Pan");
-    panNum        = new gInput(pan->x()+pan->w()+4,              tools->y(), 45, 20, "%");
-
-    pitch         = new gDial (tools->x()+42,                       volume->y()+volume->h()+4, 20, 20, "Pitch");
-    pitchNum      = new gInput(pitch->x()+pitch->w()+4,             volume->y()+volume->h()+4, 46, 20);
-    pitchToBar    = new gClick(pitchNum->x()+pitchNum->w()+4,       volume->y()+volume->h()+4, 46, 20, "To bar");
-    pitchToSong   = new gClick(pitchToBar->x()+pitchToBar->w()+4,   volume->y()+volume->h()+4, 46, 20, "To song");
-    pitchHalf     = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 21, 20, "÷");
-    pitchDouble   = new gClick(pitchHalf->x()+pitchHalf->w()+4,     volume->y()+volume->h()+4, 21, 20, "×");
-    pitchReset    = new gClick(pitchDouble->x()+pitchDouble->w()+4, volume->y()+volume->h()+4, 46, 20, "Reset");
-    reload        = new gClick(pitchReset->x()+pitchReset->w()+4,   volume->y()+volume->h()+4, 70, 20, "Reload");
-
-    chanStart     = new gInput(tools->x()+52,                    pitch->y()+pitch->h()+4, 60, 20, "Start");
-    chanEnd       = new gInput(chanStart->x()+chanStart->w()+40, pitch->y()+pitch->h()+4, 60, 20, "End");
-    resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4,      pitch->y()+pitch->h()+4, 46, 20, "Reset");
-
-  tools->end();
-  tools->resizable(new gBox(panNum->x()+panNum->w()+4, tools->y(), 80, tools->h()));
-
-  /* grid tool setup */
-
-  grid->add("(off)");
-  grid->add("2");
-  grid->add("3");
-  grid->add("4");
-  grid->add("6");
-  grid->add("8");
-  grid->add("16");
-  grid->add("32");
-  grid->add("64");
-  grid->value(G_Conf.sampleEditorGridVal);
-  grid->callback(cb_changeGrid, (void*)this);
-
-  snap->value(G_Conf.sampleEditorGridOn);
-  snap->callback(cb_enableSnap, (void*)this);
-
-  /* TODO - redraw grid if != (off) */
-
-  char buf[16];
-  sprintf(buf, "%d", ch->begin / 2); // divided by 2 because stereo
-  chanStart->value(buf);
-  chanStart->type(FL_INT_INPUT);
-  chanStart->callback(cb_setChanPos, this);
-
-  /* inputs callback: fire when they lose focus or Enter is pressed. */
-
-  chanStart->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
-  chanEnd  ->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
-
-  sprintf(buf, "%d", ch->end / 2);  // divided by 2 because stereo
-  chanEnd->value(buf);
-  chanEnd->type(FL_INT_INPUT);
-  chanEnd->callback(cb_setChanPos, this);
-
-  resetStartEnd->callback(cb_resetStartEnd, this);
-
-  volume->callback(cb_setVolume, (void*)this);
-  volume->value(ch->guiChannel->vol->value());
-
-  float dB = 20*log10(ch->volume);   // dB = 20*log_10(linear value)
-  if (dB > -INFINITY) sprintf(buf, "%.2f", dB);
-  else                sprintf(buf, "-inf");
-  volumeNum->value(buf);
-  volumeNum->align(FL_ALIGN_RIGHT);
-  volumeNum->callback(cb_setVolumeNum, (void*)this);
-
-  boost->range(1.0f, 10.0f);
-  boost->callback(cb_setBoost, (void*)this);
-  if (ch->boost > 10.f)
-    boost->value(10.0f);
-  else
-    boost->value(ch->boost);
-  boost->when(FL_WHEN_CHANGED | FL_WHEN_RELEASE);
-
-  float boost = 20*log10(ch->boost); // dB = 20*log_10(linear value)
-  sprintf(buf, "%.2f", boost);
-  boostNum->value(buf);
-  boostNum->align(FL_ALIGN_RIGHT);
-  boostNum->callback(cb_setBoostNum, (void*)this);
-
-  normalize->callback(cb_normalize, (void*)this);
-
-  pan->range(0.0f, 2.0f);
-  pan->callback(cb_panning, (void*)this);
-
-  pitch->range(0.01f, 4.0f);
-  pitch->value(ch->pitch);
-  pitch->callback(cb_setPitch, (void*)this);
-  pitch->when(FL_WHEN_RELEASE);
-
-  sprintf(buf, "%.4f", ch->pitch); // 4 digits
-  pitchNum->value(buf);
-  pitchNum->align(FL_ALIGN_RIGHT);
-  pitchNum->callback(cb_setPitchNum, (void*)this);
-  pitchNum->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
-
-  pitchToBar->callback(cb_setPitchToBar, (void*)this);
-  pitchToSong->callback(cb_setPitchToSong, (void*)this);
-  pitchHalf->callback(cb_setPitchHalf, (void*)this);
-  pitchDouble->callback(cb_setPitchDouble, (void*)this);
-  pitchReset->callback(cb_resetPitch, (void*)this);
-
-  reload->callback(cb_reload, (void*)this);
-
-  zoomOut->callback(cb_zoomOut, (void*)this);
-  zoomIn->callback(cb_zoomIn, (void*)this);
-
-  /* logical samples (aka takes) cannot be reloaded. So far. */
-
-  if (ch->wave->isLogical)
-    reload->deactivate();
-
-  if (ch->panRight < 1.0f) {
-    char buf[8];
-    sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100));
-    pan->value(ch->panRight);
-    panNum->value(buf);
-  }
-  else if (ch->panRight == 1.0f && ch->panLeft == 1.0f) {
-    pan->value(1.0f);
-    panNum->value("C");
-  }
-  else {
-    char buf[8];
-    sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100));
-    pan->value(2.0f - ch->panLeft);
-    panNum->value(buf);
-  }
-
-  panNum->align(FL_ALIGN_RIGHT);
-  panNum->readonly(1);
-  panNum->cursor_color(FL_WHITE);
-
-  gu_setFavicon(this);
-  size_range(640, 480);
-  resizable(waveTools);
-
-  label(ch->wave->name.c_str());
-
-  show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdEditor::~gdEditor()
-{
-  G_Conf.sampleEditorX = x();
-  G_Conf.sampleEditorY = y();
-  G_Conf.sampleEditorW = w();
-  G_Conf.sampleEditorH = h();
-  G_Conf.sampleEditorGridVal = grid->value();
-  G_Conf.sampleEditorGridOn  = snap->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::cb_setChanPos      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setChanPos(); }
-void gdEditor::cb_resetStartEnd   (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetStartEnd(); }
-void gdEditor::cb_setVolume       (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolume(); }
-void gdEditor::cb_setVolumeNum    (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolumeNum(); }
-void gdEditor::cb_setBoost        (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoost(); }
-void gdEditor::cb_setBoostNum     (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoostNum(); }
-void gdEditor::cb_normalize       (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_normalize(); }
-void gdEditor::cb_panning         (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_panning(); }
-void gdEditor::cb_reload          (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_reload(); }
-void gdEditor::cb_setPitch        (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitch(); }
-void gdEditor::cb_setPitchToBar   (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToBar(); }
-void gdEditor::cb_setPitchToSong  (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToSong(); }
-void gdEditor::cb_setPitchHalf    (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchHalf(); }
-void gdEditor::cb_setPitchDouble  (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchDouble(); }
-void gdEditor::cb_resetPitch      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetPitch(); }
-void gdEditor::cb_setPitchNum     (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchNum(); }
-void gdEditor::cb_zoomIn          (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomIn(); }
-void gdEditor::cb_zoomOut         (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomOut(); }
-void gdEditor::cb_changeGrid      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_changeGrid(); }
-void gdEditor::cb_enableSnap      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_enableSnap(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_enableSnap()
-{
-  waveTools->waveform->setSnap(!waveTools->waveform->getSnap());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitchToBar()
-{
-  glue_setPitch(this, ch, ch->end/(float)G_Mixer.framesPerBar, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitchToSong()
-{
-  glue_setPitch(this, ch, ch->end/(float)G_Mixer.totalFrames, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_resetPitch()
-{
-  glue_setPitch(this, ch, 1.0f, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setChanPos()
-{
-  glue_setBeginEndChannel(
-    this,
-    ch,
-    atoi(chanStart->value())*2,  // glue halves printed values
-    atoi(chanEnd->value())*2,
-    true
-  );
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_resetStartEnd()
-{
-  glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setVolume()
-{
-  glue_setVolEditor(this, ch, volume->value(), false);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setVolumeNum()
-{
-  glue_setVolEditor(this, ch, atof(volumeNum->value()), true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setBoost()
-{
-  if (Fl::event() == FL_DRAG)
-    glue_setBoost(this, ch, boost->value(), false);
-  else if (Fl::event() == FL_RELEASE) {
-    glue_setBoost(this, ch, boost->value(), false);
-  waveTools->updateWaveform();
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setBoostNum()
-{
-  glue_setBoost(this, ch, atof(boostNum->value()), true);
-  waveTools->updateWaveform();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_normalize()
-{
-  float val = wfx_normalizeSoft(ch->wave);
-  glue_setBoost(this, ch, val, false); // we pretend that a fake user turns the dial (numeric=false)
-  if (val < 0.0f)
-    boost->value(0.0f);
-  else
-  if (val > 20.0f) // a dial > than it's max value goes crazy
-    boost->value(10.0f);
-  else
-    boost->value(val);
-  waveTools->updateWaveform();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_panning()
-{
-  glue_setPanning(this, ch, pan->value());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_reload()
-{
-  if (!gdConfirmWin("Warning", "Reload sample: are you sure?"))
-    return;
-
-  /* no need for glue_loadChan, there's no gui to refresh */
-
-  ch->load(ch->wave->pathfile.c_str());
-
-  glue_setBoost(this, ch, DEFAULT_BOOST, true);
-  glue_setPitch(this, ch, gDEFAULT_PITCH, true);
-  glue_setPanning(this, ch, 1.0f);
-  pan->value(1.0f);  // glue_setPanning doesn't do it
-  pan->redraw();     // glue_setPanning doesn't do it
-
-  waveTools->waveform->stretchToWindow();
-  waveTools->updateWaveform();
-
-  glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true);
-
-  redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitch()
-{
-  glue_setPitch(this, ch, pitch->value(), false);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitchNum()
-{
-  glue_setPitch(this, ch, atof(pitchNum->value()), true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitchHalf()
-{
-  glue_setPitch(this, ch, pitch->value()/2, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_setPitchDouble()
-{
-  glue_setPitch(this, ch, pitch->value()*2, true);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_zoomIn()
-{
-  waveTools->waveform->setZoom(-1);
-  waveTools->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_zoomOut()
-{
-  waveTools->waveform->setZoom(0);
-  waveTools->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdEditor::__cb_changeGrid()
-{
-  waveTools->waveform->setGridLevel(atoi(grid->text()));
-}
diff --git a/src/gd_editor.h b/src/gd_editor.h
deleted file mode 100644 (file)
index 9ae3266..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_editor
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GD_EDITOR_H
-#define GD_EDITOR_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <math.h>
-#include "ge_window.h"
-
-
-class gdEditor : public gWindow {
-
-private:
-
-       static void cb_setChanPos    (Fl_Widget *w, void *p);
-       static void cb_resetStartEnd (Fl_Widget *w, void *p);
-       static void cb_setVolume     (Fl_Widget *w, void *p);
-       static void cb_setVolumeNum  (Fl_Widget *w, void *p);
-       static void cb_setBoost      (Fl_Widget *w, void *p);
-       static void cb_setBoostNum   (Fl_Widget *w, void *p);
-       static void cb_normalize     (Fl_Widget *w, void *p);
-       static void cb_panning       (Fl_Widget *w, void *p);
-       static void cb_reload        (Fl_Widget *w, void *p);
-       static void cb_setPitch      (Fl_Widget *w, void *p);
-       static void cb_setPitchToBar (Fl_Widget *w, void *p);
-       static void cb_setPitchToSong(Fl_Widget *w, void *p);
-       static void cb_setPitchHalf  (Fl_Widget *w, void *p);
-       static void cb_setPitchDouble(Fl_Widget *w, void *p);
-       static void cb_resetPitch    (Fl_Widget *w, void *p);
-       static void cb_setPitchNum   (Fl_Widget *w, void *p);
-       static void cb_zoomIn        (Fl_Widget *w, void *p);
-       static void cb_zoomOut       (Fl_Widget *w, void *p);
-       static void cb_changeGrid    (Fl_Widget *w, void *p);
-       static void cb_enableSnap    (Fl_Widget *w, void *p);
-       inline void __cb_setChanPos();
-       inline void __cb_resetStartEnd();
-       inline void __cb_setVolume();
-       inline void __cb_setVolumeNum();
-       inline void __cb_setBoost();
-       inline void __cb_setBoostNum();
-       inline void __cb_normalize();
-       inline void __cb_panning();
-       inline void __cb_reload();
-       inline void __cb_setPitch();
-       inline void __cb_setPitchToBar();
-       inline void __cb_setPitchToSong();
-       inline void __cb_setPitchHalf();
-       inline void __cb_setPitchDouble();
-       inline void __cb_resetPitch();
-       inline void __cb_setPitchNum();
-       inline void __cb_zoomIn();
-       inline void __cb_zoomOut();
-       inline void __cb_changeGrid();
-       inline void __cb_enableSnap();
-
-public:
-
-       gdEditor(class SampleChannel *ch);
-       ~gdEditor();
-
-       class gClick     *zoomIn;
-       class gClick     *zoomOut;
-       class gWaveTools *waveTools;
-       class gInput     *chanStart;
-       class gInput     *chanEnd;
-       class gClick             *resetStartEnd;
-       class gDial      *volume;
-       class gInput     *volumeNum;
-       class gDial      *boost;
-       class gInput     *boostNum;
-       class gClick     *normalize;
-       class gDial      *pan;
-       class gInput     *panNum;
-       class gClick             *reload;
-       class gDial              *pitch;
-       class gInput     *pitchNum;
-       class gClick     *pitchToBar;
-       class gClick     *pitchToSong;
-       class gClick     *pitchHalf;
-       class gClick     *pitchDouble;
-       class gClick     *pitchReset;
-       class gClick     *close;
-       class gChoice    *grid;
-       class gCheck     *snap;
-
-       class SampleChannel *ch;
-};
-
-#endif
diff --git a/src/gd_keyGrabber.cpp b/src/gd_keyGrabber.cpp
deleted file mode 100644 (file)
index 469adf0..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_keyGrabber
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gd_keyGrabber.h"
-#include "gg_keyboard.h"
-#include "ge_mixed.h"
-#include "gd_config.h"
-#include "ge_channel.h"
-#include "gd_mainWindow.h"
-#include "gui_utils.h"
-#include "conf.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "log.h"
-
-
-extern Conf             G_Conf;
-extern gdMainWindow *mainWin;
-
-
-gdKeyGrabber::gdKeyGrabber(Channel *ch)
-       : gWindow(300, 126, "Key configuration"), ch(ch)
-{
-       set_modal();
-       text   = new gBox(8, 8, 284, 80, "");
-       clear  = new gClick(w()-88, text->y()+text->h()+8, 80, 20, "Clear");
-       cancel = new gClick(clear->x()-88, clear->y(), 80, 20, "Close");
-       end();
-
-       clear->callback(cb_clear, (void*)this);
-       cancel->callback(cb_cancel, (void*)this);
-
-       updateText(ch->key);
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::cb_clear (Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_clear(); }
-void gdKeyGrabber::cb_cancel(Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_cancel(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::__cb_cancel()
-{
-       do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::__cb_clear()
-{
-       updateText(0);
-       setButtonLabel(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::setButtonLabel(int key)
-{
-       char tmp[2]; sprintf(tmp, "%c", key);
-       ch->guiChannel->button->copy_label(tmp);
-       ch->key = key;
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::updateText(int key)
-{
-       char tmp2[64];
-       if (key != 0)
-               sprintf(tmp2, "Press a key.\n\nCurrent binding: %c", key);
-       else
-               sprintf(tmp2, "Press a key.\n\nCurrent binding: [none]");
-       text->copy_label(tmp2);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gdKeyGrabber::handle(int e)
-{
-       int ret = Fl_Group::handle(e);
-       switch(e) {
-               case FL_KEYUP: {
-                       int x = Fl::event_key();
-                       if (strlen(Fl::event_text()) != 0
-                           && x != FL_BackSpace
-                           && x != FL_Enter
-                           && x != FL_Delete
-                           && x != FL_Tab
-                           && x != FL_End
-                           && x != ' ')
-                       {
-                               gLog("set key '%c' (%d) for channel %d\n", x, x, ch->index);
-                               setButtonLabel(x);
-                               updateText(x);
-                               break;
-                       }
-                       else
-                               gLog("invalid key\n");
-               }
-       }
-       return(ret);
-}
diff --git a/src/gd_keyGrabber.h b/src/gd_keyGrabber.h
deleted file mode 100644 (file)
index 4e4b2a3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_keyGrabber
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GD_KEYGRABBER_H
-#define GD_KEYGRABBER_H
-
-
-#include <FL/Fl.H>
-#include "ge_window.h"
-
-
-class gdKeyGrabber : public gWindow
-{
-private:
-
-       class Channel *ch;
-
-       class gBox   *text;
-       class gClick *clear;
-       class gClick *cancel;
-
-       static void cb_clear (Fl_Widget *w, void *p);
-       static void cb_cancel(Fl_Widget *w, void *p);
-       inline void __cb_clear ();
-       inline void __cb_cancel();
-
-       void setButtonLabel(int key);
-
-       void updateText(int key);
-
-public:
-
-       gdKeyGrabber(class Channel *ch);
-       int handle(int e);
-};
-
-#endif
diff --git a/src/gd_mainWindow.cpp b/src/gd_mainWindow.cpp
deleted file mode 100644 (file)
index b8fc2df..0000000
+++ /dev/null
@@ -1,672 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_mainWindow
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef __linux__
-       #include <sys/stat.h>                   // for mkdir
-#endif
-
-#include "gd_mainWindow.h"
-#include "gd_warnings.h"
-#include "gd_bpmInput.h"
-#include "gd_beatsInput.h"
-#include "gd_midiInput.h"
-#include "gg_keyboard.h"
-#include "gd_about.h"
-#include "gd_config.h"
-#include "gd_browser.h"
-#include "graphics.h"
-#include "glue.h"
-#include "mixer.h"
-#include "recorder.h"
-#include "mixerHandler.h"
-#include "pluginHost.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "init.h"
-#include "patch.h"
-#include "conf.h"
-
-#ifdef WITH_VST
-#include "gd_pluginList.h"
-#endif
-
-
-extern Mixer                    G_Mixer;
-extern Patch                    G_Patch;
-extern Conf                             G_Conf;
-extern gdMainWindow *mainWin;
-extern bool                                     G_quit;
-extern bool                             G_audio_status;
-
-#if defined(WITH_VST)
-extern PluginHost       G_PluginHost;
-#endif
-
-
-gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **argv)
-       : gWindow(W, H, title)
-{
-       Fl::visible_focus(0);
-       Fl::background(25, 25, 25);
-       Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2);    // custom box G_BOX
-
-       size_range(GUI_WIDTH, GUI_HEIGHT);
-
-       menu       = new gMenu(8, -1);
-       inOut      = new gInOut(408, 8);
-       controller = new gController(8, 39);
-       timing     = new gTiming(632, 39);
-       beatMeter  = new gBeatMeter(100, 83, 609, 20);
-       keyboard   = new gKeyboard(8, 122, w()-16, 380);
-
-       /* zone 1 - menus, and I/O tools */
-
-       Fl_Group *zone1 = new Fl_Group(8, 8, W-16, 20);
-       zone1->add(menu);
-       zone1->resizable(new Fl_Box(300, 8, 80, 20));
-       zone1->add(inOut);
-
-       /* zone 2 - controller and timing tools */
-
-       Fl_Group *zone2 = new Fl_Group(8, controller->y(), W-16, controller->h());
-       zone2->add(controller);
-       zone2->resizable(new Fl_Box(controller->x()+controller->w()+4, zone2->y(), 80, 20));
-       zone2->add(timing);
-
-       /* zone 3 - beat meter */
-
-       Fl_Group *zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h());
-       zone3->add(beatMeter);
-
-       /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
-        * a group by itself) */
-
-       resizable(keyboard);
-
-       add(zone1);
-       add(zone2);
-       add(zone3);
-       add(keyboard);
-       callback(cb_endprogram);
-       gu_setFavicon(this);
-       show(argc, argv);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { mainWin->__cb_endprogram(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMainWindow::__cb_endprogram()
-{
-       if (!gdConfirmWin("Warning", "Quit Giada: are you sure?"))
-               return;
-       init_shutdown();
-       hide();
-       delete this;
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gInOut::gInOut(int x, int y)
-       : Fl_Group(x, y, 394, 20)
-{
-       begin();
-
-#if defined(WITH_VST)
-       masterFxIn  = new gFxButton  (x, y, 20, 20, fxOff_xpm, fxOn_xpm);
-       inVol               = new gDial      (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20);
-       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
-       inToOut     = new gClick     (inMeter->x()+inMeter->w()+4, y+5, 10, 10, "");
-       outMeter    = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+5, 140, 10);
-       outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
-       masterFxOut = new gFxButton  (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm);
-#else
-       inVol               = new gDial      (x+62, y, 20, 20);
-       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
-       outMeter    = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 10);
-       outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
-#endif
-
-       end();
-
-       resizable(NULL);   // don't resize any widget
-
-       outVol->callback(cb_outVol, (void*)this);
-       outVol->value(G_Mixer.outVol);
-       inVol->callback(cb_inVol, (void*)this);
-       inVol->value(G_Mixer.inVol);
-
-#ifdef WITH_VST
-       masterFxOut->callback(cb_masterFxOut, (void*)this);
-       masterFxIn->callback(cb_masterFxIn, (void*)this);
-       inToOut->callback(cb_inToOut, (void*)this);
-       inToOut->type(FL_TOGGLE_BUTTON);
-#endif
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gInOut::cb_outVol     (Fl_Widget *v, void *p)     { ((gInOut*)p)->__cb_outVol(); }
-void gInOut::cb_inVol      (Fl_Widget *v, void *p)     { ((gInOut*)p)->__cb_inVol(); }
-#ifdef WITH_VST
-void gInOut::cb_masterFxOut(Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_masterFxOut(); }
-void gInOut::cb_masterFxIn (Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_masterFxIn(); }
-void gInOut::cb_inToOut    (Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_inToOut(); }
-#endif
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gInOut::__cb_outVol()
-{
-       glue_setOutVol(outVol->value());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gInOut::__cb_inVol()
-{
-       glue_setInVol(inVol->value());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-void gInOut::__cb_masterFxOut()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST);
-}
-
-void gInOut::__cb_masterFxIn()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST);
-}
-
-void gInOut::__cb_inToOut()
-{
-       G_Mixer.inToOut = inToOut->value();
-}
-#endif
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gInOut::refresh()
-{
-       outMeter->mixerPeak = G_Mixer.peakOut;
-       inMeter->mixerPeak  = G_Mixer.peakIn;
-       outMeter->redraw();
-       inMeter->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gMenu::gMenu(int x, int y)
-       : Fl_Group(x, y, 300, 20)
-{
-       begin();
-
-       file   = new gClick(x, y, 70, 21, "file");
-       edit   = new gClick(file->x()+file->w()+4,  y, 70, 21, "edit");
-       config = new gClick(edit->x()+edit->w()+4, y, 70, 21, "config");
-       about    = new gClick(config->x()+config->w()+4, y, 70, 21, "about");
-
-       end();
-
-       resizable(NULL);   // don't resize any widget
-
-       about->callback(cb_about, (void*)this);
-       file->callback(cb_file, (void*)this);
-       edit->callback(cb_edit, (void*)this);
-       config->callback(cb_config, (void*)this);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); }
-void gMenu::cb_config(Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_config(); }
-void gMenu::cb_file  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); }
-void gMenu::cb_edit  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMenu::__cb_about()
-{
-       gu_openSubWindow(mainWin, new gdAbout(), WID_ABOUT);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMenu::__cb_config()
-{
-       gu_openSubWindow(mainWin, new gdConfig(380, 370), WID_CONFIG);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMenu::__cb_file()
-{
-       /* An Fl_Menu_Button is made of many Fl_Menu_Item */
-
-       Fl_Menu_Item menu[] = {
-               {"Open patch or project..."},
-               {"Save patch..."},
-               {"Save project..."},
-               {"Quit Giada"},
-               {0}
-       };
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(11);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = menu->popup(Fl::event_x(),      Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-
-       if (strcmp(m->label(), "Open patch or project...") == 0) {
-               gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath, 0, BROWSER_LOAD_PATCH);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
-               return;
-       }
-       if (strcmp(m->label(), "Save patch...") == 0) {
-               if (G_Mixer.hasLogicalSamples() || G_Mixer.hasEditedSamples())
-                       if (!gdConfirmWin("Warning", "You should save a project in order to store\nyour takes and/or processed samples."))
-                               return;
-               gWindow *childWin = new gdBrowser("Save Patch", G_Conf.patchPath, 0, BROWSER_SAVE_PATCH);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
-               return;
-       }
-       if (strcmp(m->label(), "Save project...") == 0) {
-               gWindow *childWin = new gdBrowser("Save Project", G_Conf.patchPath, 0, BROWSER_SAVE_PROJECT);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
-               return;
-       }
-       if (strcmp(m->label(), "Quit Giada") == 0) {
-               mainWin->do_callback();
-               return;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMenu::__cb_edit()
-{
-       Fl_Menu_Item menu[] = {
-               {"Clear all samples"},
-               {"Clear all actions"},
-               {"Remove empty columns"},
-               {"Reset to init state"},
-               {"Setup global MIDI input..."},
-               {0}
-       };
-
-       /* clear all actions disabled if no recs, clear all samples disabled
-        * if no samples. */
-
-       menu[1].deactivate();
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               if (G_Mixer.channels.at(i)->hasActions) {
-                       menu[1].activate();
-                       break;
-               }
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
-                       if (((SampleChannel*)G_Mixer.channels.at(i))->wave != NULL) {
-                               menu[0].activate();
-                               break;
-                       }
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(11);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = menu->popup(Fl::event_x(),      Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-       if (strcmp(m->label(), "Clear all samples") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all samples: are you sure?"))
-                       return;
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
-               glue_clearAllSamples();
-               return;
-       }
-       if (strcmp(m->label(), "Clear all actions") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-                       return;
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
-               glue_clearAllRecs();
-               return;
-       }
-       if (strcmp(m->label(), "Reset to init state") == 0) {
-               if (!gdConfirmWin("Warning", "Reset to init state: are you sure?"))
-                       return;
-               gu_closeAllSubwindows();
-               glue_resetToInitState();
-               return;
-       }
-       if (strcmp(m->label(), "Remove empty columns") == 0) {
-               mainWin->keyboard->organizeColumns();
-               return;
-       }
-       if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0);
-               return;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gController::gController(int x, int y)
-       : Fl_Group(x, y, 131, 25)
-{
-       begin();
-
-       rewind    = new gClick(x,  y, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
-       play      = new gClick(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm);
-       recAction = new gClick(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm);
-       recInput  = new gClick(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm);
-       metronome = new gClick(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm);
-
-       end();
-
-       resizable(NULL);   // don't resize any widget
-
-       rewind->callback(cb_rewind, (void*)this);
-
-       play->callback(cb_play);
-       play->type(FL_TOGGLE_BUTTON);
-
-       recAction->callback(cb_recAction, (void*)this);
-       recAction->type(FL_TOGGLE_BUTTON);
-
-       recInput->callback(cb_recInput, (void*)this);
-       recInput->type(FL_TOGGLE_BUTTON);
-
-       metronome->callback(cb_metronome);
-       metronome->type(FL_TOGGLE_BUTTON);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::cb_rewind   (Fl_Widget *v, void *p) { ((gController*)p)->__cb_rewind(); }
-void gController::cb_play     (Fl_Widget *v, void *p) { ((gController*)p)->__cb_play(); }
-void gController::cb_recAction(Fl_Widget *v, void *p) { ((gController*)p)->__cb_recAction(); }
-void gController::cb_recInput (Fl_Widget *v, void *p) { ((gController*)p)->__cb_recInput(); }
-void gController::cb_metronome(Fl_Widget *v, void *p) { ((gController*)p)->__cb_metronome(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::__cb_rewind()
-{
-       glue_rewindSeq();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::__cb_play()
-{
-       glue_startStopSeq();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::__cb_recAction()
-{
-       glue_startStopActionRec();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::__cb_recInput()
-{
-       glue_startStopInputRec();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::__cb_metronome()
-{
-       glue_startStopMetronome();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::updatePlay(int v)
-{
-       play->value(v);
-       play->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::updateMetronome(int v)
-{
-       metronome->value(v);
-       metronome->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::updateRecInput(int v)
-{
-       recInput->value(v);
-       recInput->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gController::updateRecAction(int v)
-{
-       recAction->value(v);
-       recAction->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gTiming::gTiming(int x, int y)
-       : Fl_Group(x, y, 170, 15)
-{
-       begin();
-
-       quantizer  = new gChoice(x, y, 40, 15, "", false);
-       bpm        = new gClick (quantizer->x()+quantizer->w()+4,  y, 40, 15);
-       meter      = new gClick (bpm->x()+bpm->w()+8,  y, 40, 15, "4/1");
-       multiplier = new gClick (meter->x()+meter->w()+4, y, 15, 15, "", beatsMultiplyOff_xpm, beatsMultiplyOn_xpm);
-       divider    = new gClick (multiplier->x()+multiplier->w()+4, y, 15, 15, "÷", beatsDivideOff_xpm, beatsDivideOn_xpm);
-
-       end();
-
-       resizable(NULL);   // don't resize any widget
-
-       char buf[6]; snprintf(buf, 6, "%f", G_Mixer.bpm);
-       bpm->copy_label(buf);
-
-       bpm->callback(cb_bpm, (void*)this);
-       meter->callback(cb_meter, (void*)this);
-       multiplier->callback(cb_multiplier, (void*)this);
-       divider->callback(cb_divider, (void*)this);
-
-       quantizer->add("off", 0, cb_quantizer, (void*)this);
-       quantizer->add("1b",  0, cb_quantizer, (void*)this);
-       quantizer->add("2b",  0, cb_quantizer, (void*)this);
-       quantizer->add("3b",  0, cb_quantizer, (void*)this);
-       quantizer->add("4b",  0, cb_quantizer, (void*)this);
-       quantizer->add("6b",  0, cb_quantizer, (void*)this);
-       quantizer->add("8b",  0, cb_quantizer, (void*)this);
-       quantizer->value(0); //  "off" by default
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::cb_bpm       (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); }
-void gTiming::cb_meter     (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_meter(); }
-void gTiming::cb_quantizer (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_quantizer(); }
-void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multiplier(); }
-void gTiming::cb_divider   (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::__cb_bpm()
-{
-       gu_openSubWindow(mainWin, new gdBpmInput(bpm->label()), WID_BPM);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::__cb_meter()
-{
-       gu_openSubWindow(mainWin, new gdBeatsInput(), WID_BEATS);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::__cb_quantizer()
-{
-       glue_quantize(quantizer->value());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::__cb_multiplier()
-{
-       glue_beatsMultiply();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::__cb_divider()
-{
-       glue_beatsDivide();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::setBpm(const char *v)
-{
-       bpm->copy_label(v);
-}
-
-
-void gTiming::setBpm(float v)
-{
-       char buf[6];
-       sprintf(buf, "%.01f", v);  // only 1 decimal place (e.g. 120.0)
-       bpm->copy_label(buf);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gTiming::setMeter(int beats, int bars)
-{
-       char buf[8];
-       sprintf(buf, "%d/%d", beats, bars);
-       meter->copy_label(buf);
-}
diff --git a/src/gd_mainWindow.h b/src/gd_mainWindow.h
deleted file mode 100644 (file)
index 0361d5d..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- * gd_mainWindow
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_MAINWINDOW_H
-#define GD_MAINWINDOW_H
-
-
-#include <FL/Fl.H>
-#include <FL/x.H>
-#include "ge_mixed.h"
-#include "ge_window.h"
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gdMainWindow : public gWindow
-{
-private:
-
-       static void cb_endprogram  (Fl_Widget *v, void *p);
-       inline void __cb_endprogram();
-
-public:
-
-       class gKeyboard   *keyboard;
-       class gBeatMeter  *beatMeter;
-       class gMenu       *menu;
-       class gInOut      *inOut;
-       class gController *controller;
-       class gTiming     *timing;
-
-       gdMainWindow(int w, int h, const char *title, int argc, char **argv);
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gInOut : public Fl_Group
-{
-private:
-
-       class gSoundMeter *outMeter;
-       class gSoundMeter *inMeter;
-       class gBeatMeter  *beatMeter;
-       class gDial                             *outVol;
-       class gDial                             *inVol;
-#ifdef WITH_VST
-       class gFxButton         *masterFxOut;
-       class gFxButton         *masterFxIn;
-       class gClick      *inToOut;
-#endif
-
-       static void cb_outVol     (Fl_Widget *v, void *p);
-       static void cb_inVol      (Fl_Widget *v, void *p);
-#ifdef WITH_VST
-       static void cb_masterFxOut(Fl_Widget *v, void *p);
-       static void cb_masterFxIn (Fl_Widget *v, void *p);
-       static void cb_inToOut    (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_outVol     ();
-       inline void __cb_inVol      ();
-#ifdef WITH_VST
-       inline void __cb_masterFxOut();
-       inline void __cb_masterFxIn ();
-       inline void __cb_inToOut    ();
-#endif
-
-public:
-
-       gInOut(int x, int y);
-
-       void refresh();
-
-       inline void setOutVol(float v) { outVol->value(v); }
-       inline void setInVol (float v) { inVol->value(v); }
-#ifdef WITH_VST
-       inline void setMasterFxOutFull(bool v) { masterFxOut->full = v; masterFxOut->redraw(); }
-       inline void setMasterFxInFull(bool v)  { masterFxIn->full = v; masterFxIn->redraw(); }
-#endif
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gMenu : public Fl_Group
-{
-private:
-
-       class gClick *file;
-       class gClick *edit;
-       class   gClick *config;
-       class gClick *about;
-
-       static void cb_about (Fl_Widget *v, void *p);
-       static void cb_config(Fl_Widget *v, void *p);
-       static void cb_file  (Fl_Widget *v, void *p);
-       static void cb_edit  (Fl_Widget *v, void *p);
-
-       inline void __cb_about ();
-       inline void __cb_config();
-       inline void __cb_file  ();
-       inline void __cb_edit  ();
-
-public:
-
-       gMenu(int x, int y);
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gController : public Fl_Group
-{
-private:
-
-       class gClick *rewind;
-       class gClick *play;
-       class gClick *recAction;
-       class gClick *recInput;
-       class gClick *metronome;
-
-       static void cb_rewind   (Fl_Widget *v, void *p);
-       static void cb_play     (Fl_Widget *v, void *p);
-       static void cb_recAction(Fl_Widget *v, void *p);
-       static void cb_recInput (Fl_Widget *v, void *p);
-       static void cb_metronome(Fl_Widget *v, void *p);
-
-       inline void __cb_rewind   ();
-       inline void __cb_play     ();
-       inline void __cb_recAction();
-       inline void __cb_recInput ();
-       inline void __cb_metronome();
-
-public:
-
-       gController(int x, int y);
-
-       void updatePlay     (int v);
-       void updateMetronome(int v);
-       void updateRecInput (int v);
-       void updateRecAction(int v);
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gTiming : public Fl_Group
-{
-private:
-
-       class gClick   *bpm;
-       class gClick   *meter;
-       class gChoice  *quantizer;
-       class gClick   *multiplier;
-       class gClick   *divider;
-
-       static void cb_bpm       (Fl_Widget *v, void *p);
-       static void cb_meter     (Fl_Widget *v, void *p);
-       static void cb_quantizer (Fl_Widget *v, void *p);
-       static void cb_multiplier(Fl_Widget *v, void *p);
-       static void cb_divider   (Fl_Widget *v, void *p);
-
-       inline void __cb_bpm();
-       inline void __cb_meter();
-       inline void __cb_quantizer();
-       inline void __cb_multiplier();
-       inline void __cb_divider();
-
-public:
-
-       gTiming(int x, int y);
-
-       void setBpm(const char *v);
-       void setBpm(float v);
-       void setMeter(int beats, int bars);
-};
-
-
-#endif
diff --git a/src/gd_midiInput.cpp b/src/gd_midiInput.cpp
deleted file mode 100644 (file)
index 5d41ae1..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiInput
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gd_midiInput.h"
-#include "ge_mixed.h"
-#include "ge_midiIoTools.h"
-#include "gui_utils.h"
-#include "kernelMidi.h"
-#include "conf.h"
-#include "sampleChannel.h"
-#include "log.h"
-
-
-extern Conf G_Conf;
-
-
-gdMidiInput::gdMidiInput(int w, int h, const char *title)
-       : gWindow(w, h, title)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdMidiInput::~gdMidiInput() {
-       kernelMidi::stopMidiLearn();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInput::stopMidiLearn(gLearner *learner) {
-       kernelMidi::stopMidiLearn();
-       learner->updateValue();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
-       *param = msg;
-       stopMidiLearn(l);
-       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInput::cb_learn(uint32_t msg, void *d) {
-       cbData *data = (cbData*) d;
-       gdMidiInput   *window  = (gdMidiInput*) data->window;
-       gLearner      *learner = data->learner;
-       uint32_t      *param   = learner->param;
-       window->__cb_learn(param, msg, learner);
-       free(data);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiInput*)p)->__cb_close(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInput::__cb_close() {
-       do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
-       :       gdMidiInput(300, 206, "MIDI Input Setup"),
-               ch(ch)
-{
-       char title[64];
-       sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1);
-       label(title);
-
-       set_modal();
-
-       enable = new gCheck(8, 8, 120, 20, "enable MIDI input");
-       new gLearner(8,  30, w()-16, "key press",   cb_learn, &ch->midiInKeyPress);
-       new gLearner(8,  54, w()-16, "key release", cb_learn, &ch->midiInKeyRel);
-       new gLearner(8,  78, w()-16, "key kill",    cb_learn, &ch->midiInKill);
-       new gLearner(8, 102, w()-16, "mute",        cb_learn, &ch->midiInMute);
-       new gLearner(8, 126, w()-16, "solo",        cb_learn, &ch->midiInSolo);
-       new gLearner(8, 150, w()-16, "volume",      cb_learn, &ch->midiInVolume);
-       int yy = 178;
-
-       if (ch->type == CHANNEL_SAMPLE) {
-               size(300, 254);
-               new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
-               new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
-               yy = 226;
-       }
-
-       ok = new gButton(w()-88, yy, 80, 20, "Close");
-       ok->callback(cb_close, (void*)this);
-
-       enable->value(ch->midiIn);
-       enable->callback(cb_enable, (void*)this);
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiInputChannel*)p)->__cb_enable(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiInputChannel::__cb_enable() {
-       ch->midiIn = enable->value();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdMidiInputMaster::gdMidiInputMaster()
-       : gdMidiInput(300, 256, "MIDI Input Setup (global)")
-{
-       set_modal();
-
-       new gLearner(8,   8, w()-16, "rewind",           &cb_learn, &G_Conf.midiInRewind);
-       new gLearner(8,  32, w()-16, "play/stop",        &cb_learn, &G_Conf.midiInStartStop);
-       new gLearner(8,  56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec);
-       new gLearner(8,  80, w()-16, "input recording",  &cb_learn, &G_Conf.midiInInputRec);
-       new gLearner(8, 104, w()-16, "metronome",        &cb_learn, &G_Conf.midiInMetronome);
-       new gLearner(8, 128, w()-16, "input volume",     &cb_learn, &G_Conf.midiInVolumeIn);
-       new gLearner(8, 152, w()-16, "output volume",    &cb_learn, &G_Conf.midiInVolumeOut);
-       new gLearner(8, 176, w()-16, "sequencer ×2",     &cb_learn, &G_Conf.midiInBeatDouble);
-       new gLearner(8, 200, w()-16, "sequencer ÷2",     &cb_learn, &G_Conf.midiInBeatHalf);
-       ok = new gButton(w()-88, 228, 80, 20, "Close");
-
-       ok->callback(cb_close, (void*)this);
-
-       gu_setFavicon(this);
-       show();
-}
diff --git a/src/gd_midiInput.h b/src/gd_midiInput.h
deleted file mode 100644 (file)
index 91bdea1..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiInput
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GD_MIDI_INPUT_H
-#define GD_MIDI_INPUT_H
-
-
-#include "ge_window.h"
-#include "kernelMidi.h"
-#include "utils.h"
-#include "ge_mixed.h"
-
-
-class gdMidiInput : public gWindow
-{
-protected:
-
-       gClick *ok;
-
-       void stopMidiLearn(class gLearner *l);
-
-       /* cb_learn
-        * callback attached to kernelMidi to learn various actions. */
-
-       static void cb_learn  (uint32_t msg, void *data);
-       inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l);
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-public:
-
-       gdMidiInput(int w, int h, const char *title);
-       ~gdMidiInput();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdMidiInputChannel : public gdMidiInput
-{
-private:
-
-       class Channel *ch;
-
-       gCheck *enable;
-
-
-       //gVector <gLearner *> items; for future use, with vst parameters
-
-       static void cb_enable  (Fl_Widget *w, void *p);
-       inline void __cb_enable();
-
-public:
-
-       gdMidiInputChannel(class Channel *ch);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdMidiInputMaster : public gdMidiInput
-{
-public:
-
-       gdMidiInputMaster();
-};
-
-
-#endif
diff --git a/src/gd_midiOutput.cpp b/src/gd_midiOutput.cpp
deleted file mode 100644 (file)
index b01f6f6..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiOutput
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gd_midiOutput.h"
-#include "ge_mixed.h"
-#include "ge_channel.h"
-#include "ge_midiIoTools.h"
-#include "gg_keyboard.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "conf.h"
-#include "midiChannel.h"
-#include "gui_utils.h"
-
-
-extern Conf    G_Conf;
-
-
-gdMidiOutput::gdMidiOutput(int w, int h)
-       //: gWindow(300, 64, "Midi Output Setup")
-       : gWindow(w, h, "Midi Output Setup")
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::stopMidiLearn(gLearner *learner) {
-       kernelMidi::stopMidiLearn();
-       learner->updateValue();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
-       *param = msg;
-       stopMidiLearn(l);
-       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::cb_learn(uint32_t msg, void *d) {
-       cbData *data = (cbData*) d;
-       gdMidiOutput  *window  = (gdMidiOutput*) data->window;
-       gLearner      *learner = data->learner;
-       uint32_t      *param   = learner->param;
-       window->__cb_learn(param, msg, learner);
-       free(data);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiOutput*)p)->__cb_close(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::__cb_close() {
-       do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p)  {
-       ((gdMidiOutput*)p)->__cb_enableLightning();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::__cb_enableLightning() {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutput::setTitle(int chanNum)
-{
-       char title[64];
-       sprintf(title, "MIDI Output Setup (channel %d)", chanNum);
-       copy_label(title);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch)
-       : gdMidiOutput(300, 168), ch(ch)
-{
-       setTitle(ch->index+1);
-       begin();
-
-       enableOut   = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output");
-       chanListOut = new gChoice(w()-108, y()+8, 100, 20);
-
-       enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output");
-       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+8,  w()-16, "playing", cb_learn, &ch->midiOutLplaying);
-       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",    cb_learn, &ch->midiOutLmute);
-       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",    cb_learn, &ch->midiOutLsolo);
-
-       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
-
-       end();
-
-       chanListOut->add("Channel 1");
-       chanListOut->add("Channel 2");
-       chanListOut->add("Channel 3");
-       chanListOut->add("Channel 4");
-       chanListOut->add("Channel 5");
-       chanListOut->add("Channel 6");
-       chanListOut->add("Channel 7");
-       chanListOut->add("Channel 8");
-       chanListOut->add("Channel 9");
-       chanListOut->add("Channel 10");
-       chanListOut->add("Channel 11");
-       chanListOut->add("Channel 12");
-       chanListOut->add("Channel 13");
-       chanListOut->add("Channel 14");
-       chanListOut->add("Channel 15");
-       chanListOut->add("Channel 16");
-       chanListOut->value(0);
-
-       if (ch->midiOut)
-               enableOut->value(1);
-       else
-               chanListOut->deactivate();
-
-       if (ch->midiOutL)
-               enableLightning->value(1);
-
-       chanListOut->value(ch->midiOutChan);
-
-       enableOut->callback(cb_enableChanList, (void*)this);
-       close->callback(cb_close, (void*)this);
-
-       set_modal();
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutputMidiCh::cb_close         (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); }
-void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutputMidiCh::__cb_enableChanList() {
-       enableOut->value() ? chanListOut->activate() : chanListOut->deactivate();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutputMidiCh::__cb_close() {
-       ch->midiOut     = enableOut->value();
-       ch->midiOutChan = chanListOut->value();
-       ch->midiOutL    = enableLightning->value();
-       ch->guiChannel->update();
-       do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch)
-       : gdMidiOutput(300, 140), ch(ch)
-{
-       setTitle(ch->index+1);
-
-       enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output");
-       new gLearner(8,  enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying);
-       new gLearner(8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",   cb_learn, &ch->midiOutLmute);
-       new gLearner(8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",   cb_learn, &ch->midiOutLsolo);
-
-       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
-       close->callback(cb_close, (void*)this);
-
-       enableLightning->value(ch->midiOutL);
-       enableLightning->callback(cb_enableLightning, (void*)this);
-
-       set_modal();
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMidiOutputSampleCh::__cb_close() {
-       ch->midiOutL = enableLightning->value();
-       do_callback();
-}
diff --git a/src/gd_midiOutput.h b/src/gd_midiOutput.h
deleted file mode 100644 (file)
index 8dd2fd6..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* ----------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiOutput
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GD_MIDI_OUTPUT_H
-#define GD_MIDI_OUTPUT_H
-
-
-#include <FL/Fl.H>
-#include <stdint.h>
-#include "ge_window.h"
-
-
-/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI
-output master is managed by the configuration window, hence gdMidiOutput deals
-only with channels.
-
-Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set.
-In addition MidiOutputMidiCh has the MIDI message output box. */
-
-/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another
-parent class gdMidiIO to inherit from */
-
-class gdMidiOutput : public gWindow
-{
-protected:
-
-       class gClick *close;
-       class gCheck *enableLightning;
-
-       void stopMidiLearn(class gLearner *l);
-
-       /* cb_learn
-        * callback attached to kernelMidi to learn various actions. */
-
-       static void cb_learn  (uint32_t msg, void *data);
-       inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l);
-
-       /* cb_close
-       close current window. */
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-       /* cb_enableLightning
-       enable MIDI lightning output. */
-
-       static void cb_enableLightning  (Fl_Widget *w, void *p);
-       inline void __cb_enableLightning();
-
-       /* setTitle
-        * set window title. */
-
-       void setTitle(int chanNum);
-
-public:
-
-       gdMidiOutput(int w, int h);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdMidiOutputMidiCh : public gdMidiOutput
-{
-private:
-
-       static void cb_enableChanList  (Fl_Widget *w, void *p);
-       inline void __cb_enableChanList();
-
-       /* __cb_close
-       override parent method, we need to do more stuff on close. */
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-       class gCheck  *enableOut;
-       class gChoice *chanListOut;
-
-       class MidiChannel *ch;
-
-public:
-
-       gdMidiOutputMidiCh(class MidiChannel *ch);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdMidiOutputSampleCh : public gdMidiOutput
-{
-private:
-
-       class SampleChannel *ch;
-
-       /* __cb_close
-       override parent method, we need to do more stuff on close. */
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-public:
-
-       gdMidiOutputSampleCh(class SampleChannel *ch);
-};
-
-#endif
diff --git a/src/gd_pluginList.cpp b/src/gd_pluginList.cpp
deleted file mode 100644 (file)
index ade532d..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginList
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-#include "gd_pluginList.h"
-#include "gd_pluginWindow.h"
-#include "gd_pluginWindowGUI.h"
-#include "gd_browser.h"
-#include "gd_mainWindow.h"
-#include "ge_mixed.h"
-#include "gui_utils.h"
-#include "utils.h"
-#include "conf.h"
-#include "graphics.h"
-#include "pluginHost.h"
-#include "mixer.h"
-#include "channel.h"
-#include "ge_channel.h"
-
-
-extern Conf          G_Conf;
-extern PluginHost    G_PluginHost;
-extern gdMainWindow *mainWin;
-
-
-gdPluginList::gdPluginList(int stackType, Channel *ch)
- : gWindow(468, 204), ch(ch), stackType(stackType)
-{
-
-       if (G_Conf.pluginListX)
-               resize(G_Conf.pluginListX, G_Conf.pluginListY, w(), h());
-
-       list = new Fl_Scroll(8, 8, 476, 188);
-       list->type(Fl_Scroll::VERTICAL);
-       list->scrollbar.color(COLOR_BG_0);
-       list->scrollbar.selection_color(COLOR_BG_1);
-       list->scrollbar.labelcolor(COLOR_BD_1);
-       list->scrollbar.slider(G_BOX);
-
-       list->begin();
-               refreshList();
-       list->end();
-
-       end();
-       set_non_modal();
-
-  /* TODO - awful stuff... we should subclass into gdPluginListChannel and
-  gdPluginListMaster */
-
-       if (stackType == PluginHost::MASTER_OUT)
-               label("Master Out Plugins");
-       else
-       if (stackType == PluginHost::MASTER_IN)
-               label("Master In Plugins");
-       else {
-               char tmp[32];
-               sprintf(tmp, "Channel %d Plugins", ch->index+1);
-               copy_label(tmp);
-       }
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdPluginList::~gdPluginList() {
-       G_Conf.pluginListX = x();
-       G_Conf.pluginListY = y();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::cb_addPlugin(Fl_Widget *v, void *p)   { ((gdPluginList*)p)->__cb_addPlugin(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) {
-
-       /* note: this callback is fired by gdBrowser. Close its window first,
-        * by calling the parent (pluginList) and telling it to delete its
-        * subwindow (i.e. gdBrowser). */
-
-       gWindow *child = (gWindow*) v;
-       if (child->getParent() != NULL)
-               (child->getParent())->delSubWindow(child);
-
-       /* finally refresh plugin list: void *p is a pointer to gdPluginList.
-        * This callback works even when you click 'x' to close the window...
-        * well, who cares */
-
-       ((gdPluginList*)p)->refreshList();
-       ((gdPluginList*)p)->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::__cb_addPlugin() {
-
-       /* the usual callback that gWindow adds to each subwindow in this case
-        * is not enough, because when we close the browser the plugin list
-        * must be redrawn. We have a special callback, cb_refreshList, which
-        * we add to gdBrowser. It does exactly what we need. */
-
-       gdBrowser *b = new gdBrowser("Browse Plugin", G_Conf.pluginPath, ch, BROWSER_LOAD_PLUGIN, stackType);
-       addSubWindow(b);
-       b->callback(cb_refreshList, (void*)this);       // 'this' refers to gdPluginList
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::refreshList() {
-
-       /* delete the previous list */
-
-       list->clear();
-       list->scroll_to(0, 0);
-
-       /* add new buttons, as many as the plugin in pluginHost::stack + 1,
-        * the 'add new' button. Warning: if ch == NULL we are working with
-        * master in/master out stacks. */
-
-       int numPlugins = G_PluginHost.countPlugins(stackType, ch);
-       int i = 0;
-
-       while (i<numPlugins) {
-               Plugin   *pPlugin  = G_PluginHost.getPluginByIndex(i, stackType, ch);
-               gdPlugin *gdp      = new gdPlugin(this, pPlugin, list->x(), list->y()-list->yposition()+(i*24), 800);
-               list->add(gdp);
-               i++;
-       }
-
-       int addPlugY = numPlugins == 0 ? 90 : list->y()-list->yposition()+(i*24);
-       addPlugin = new gClick(8, addPlugY, 452, 20, "-- add new plugin --");
-       addPlugin->callback(cb_addPlugin, (void*)this);
-       list->add(addPlugin);
-
-       /* if num(plugins) > 7 make room for the side scrollbar.
-        * Scrollbar.width = 20 + 4(margin) */
-
-       if (i>7)
-               size(492, h());
-       else
-               size(468, h());
-
-       redraw();
-
-  /* set 'full' flag to FX button */
-  
-  /* TODO - awful stuff... we should subclass into gdPluginListChannel and
-  gdPluginListMaster */
-
-       if (stackType == PluginHost::MASTER_OUT) {
-    mainWin->inOut->setMasterFxOutFull(G_PluginHost.countPlugins(stackType, ch) > 0);
-  }
-       else
-       if (stackType == PluginHost::MASTER_IN) {
-    mainWin->inOut->setMasterFxInFull(G_PluginHost.countPlugins(stackType, ch) > 0);
-  }
-       else {
-    ch->guiChannel->fx->full = G_PluginHost.countPlugins(stackType, ch) > 0;
-    ch->guiChannel->fx->redraw();
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdPlugin::gdPlugin(gdPluginList *gdp, Plugin *p, int X, int Y, int W)
-       : Fl_Group(X, Y, W, 20), pParent(gdp), pPlugin (p)
-{
-       begin();
-       button    = new gButton(8, y(), 220, 20);
-       program   = new gChoice(button->x()+button->w()+4, y(), 132, 20);
-       bypass    = new gButton(program->x()+program->w()+4, y(), 20, 20);
-       shiftUp   = new gButton(bypass->x()+bypass->w()+4, y(), 20, 20, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm);
-       shiftDown = new gButton(shiftUp->x()+shiftUp->w()+4, y(), 20, 20, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm);
-       remove    = new gButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm);
-       end();
-
-       if (pPlugin->status != 1) {  // bad state
-               char name[256];
-               sprintf(name, "* %s *", gBasename(pPlugin->pathfile).c_str());
-               button->copy_label(name);
-       }
-       else {
-               char name[256];
-               pPlugin->getProduct(name);
-               if (strcmp(name, " ")==0)
-                       pPlugin->getName(name);
-
-               button->copy_label(name);
-               button->callback(cb_openPluginWindow, (void*)this);
-
-               program->callback(cb_setProgram, (void*)this);
-
-               /* loading vst programs */
-               /* FIXME - max programs = 128 (unknown source) */
-
-               for (int i=0; i<64; i++) {
-                       char out[kVstMaxProgNameLen];
-                       pPlugin->getProgramName(i, out);
-                       for (int j=0; j<kVstMaxProgNameLen; j++)  // escape FLTK special chars
-                               if (out[j] == '/' || out[j] == '\\' || out[j] == '&' || out[j] == '_')
-                                       out[j] = '-';
-                       if (strlen(out) > 0)
-                               program->add(out);
-               }
-               if (program->size() == 0) {
-                       program->add("-- no programs --\0");
-                       program->deactivate();
-               }
-               if (pPlugin->getProgram() == -1)
-                       program->value(0);
-               else
-                       program->value(pPlugin->getProgram());
-
-               bypass->callback(cb_setBypass, (void*)this);
-               bypass->type(FL_TOGGLE_BUTTON);
-               bypass->value(pPlugin->bypass ? 0 : 1);
-       }
-
-       shiftUp->callback(cb_shiftUp, (void*)this);
-       shiftDown->callback(cb_shiftDown, (void*)this);
-       remove->callback(cb_removePlugin, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::cb_removePlugin    (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_removePlugin(); }
-void gdPlugin::cb_openPluginWindow(Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_openPluginWindow(); }
-void gdPlugin::cb_setBypass       (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_setBypass(); }
-void gdPlugin::cb_shiftUp         (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_shiftUp(); }
-void gdPlugin::cb_shiftDown       (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_shiftDown(); }
-void gdPlugin::cb_setProgram      (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_setProgram(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_shiftUp() {
-
-       /*nothing to do if there's only one plugin */
-
-       if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1)
-               return;
-
-       int pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
-
-       if (pluginIndex == 0)  // first of the stack, do nothing
-               return;
-
-       G_PluginHost.swapPlugin(pluginIndex, pluginIndex-1, pParent->stackType, pParent->ch);
-       pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_shiftDown() {
-
-       /*nothing to do if there's only one plugin */
-
-       if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1)
-               return;
-
-       unsigned pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
-       unsigned stackSize   = (G_PluginHost.getStack(pParent->stackType, pParent->ch))->size;
-
-       if (pluginIndex == stackSize-1)  // last one in the stack, do nothing
-               return;
-
-       G_PluginHost.swapPlugin(pluginIndex, pluginIndex+1, pParent->stackType, pParent->ch);
-       pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_removePlugin() {
-
-       /* os x hack: show window before deleting it */
-
-#ifdef __APPLE__
-       gdPluginWindowGUImac* w = (gdPluginWindowGUImac*) pParent->getChild(pPlugin->getId()+1);
-       if (w)
-               w->show();
-#endif
-
-       /* any subwindow linked to the plugin must be destroyed */
-
-       pParent->delSubWindow(pPlugin->getId()+1);
-       G_PluginHost.freePlugin(pPlugin->getId(), pParent->stackType, pParent->ch);
-       pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_openPluginWindow() {
-
-       /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved
-        * for the window 'add plugin'. */
-
-       /* TODO - at the moment you can open a window for each plugin in the stack.
-        * This is not consistent with the rest of the gui. You can avoid this by
-        * calling
-        *
-        * gu_openSubWindow(this, new gdPluginWindow(pPlugin), WID_FX);
-        *
-        * instead of the following code.
-        *
-        * EDIT 2 - having only 1 plugin window would be very uncomfortable */
-
-       if (!pParent->hasWindow(pPlugin->getId()+1)) {
-               gWindow *w;
-               if (pPlugin->hasGui())
-#ifdef __APPLE__
-                       w = new gdPluginWindowGUImac(pPlugin);
-#else
-                       w = new gdPluginWindowGUI(pPlugin);
-#endif
-               else
-                       w = new gdPluginWindow(pPlugin);
-               w->setId(pPlugin->getId()+1);
-               pParent->addSubWindow(w);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_setBypass() {
-       pPlugin->bypass = !pPlugin->bypass;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_setProgram() {
-       pPlugin->setProgram(program->value());
-}
-
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_pluginList.h b/src/gd_pluginList.h
deleted file mode 100644 (file)
index 33ac4a1..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginList
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-#ifndef __GD_PLUGINLIST_H__
-#define __GD_PLUGINLIST_H__
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include "ge_window.h"
-
-
-class gdPluginList : public gWindow {
-
-private:
-
-       class gClick *addPlugin;
-       Fl_Scroll    *list;
-
-       //gVector<class gdPluginWindow *> subWindows;
-
-       static void cb_addPlugin          (Fl_Widget *v, void *p);
-       inline void __cb_addPlugin        ();
-
-public:
-
-       class Channel *ch;      // ch == NULL ? masterOut
-       int   stackType;
-
-       gdPluginList(int stackType, class Channel *ch=NULL);
-       ~gdPluginList();
-
-       /* special callback, passed to browser. When closed (i.e. plugin
-        * has been selected) the same browser will refresh this window. */
-
-       static void cb_refreshList(Fl_Widget*, void*);
-
-       void refreshList();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdPlugin : public Fl_Group {
-
-private:
-
-       class  gdPluginList *pParent;
-       class  Plugin       *pPlugin;
-
-       static void cb_removePlugin       (Fl_Widget *v, void *p);
-       static void cb_openPluginWindow   (Fl_Widget *v, void *p);
-       static void cb_setBypass          (Fl_Widget *v, void *p);
-       static void cb_shiftUp            (Fl_Widget *v, void *p);
-       static void cb_shiftDown          (Fl_Widget *v, void *p);
-       static void cb_setProgram         (Fl_Widget *v, void *p);
-       inline void __cb_removePlugin     ();
-       inline void __cb_openPluginWindow ();
-       inline void __cb_setBypass        ();
-       inline void __cb_shiftUp          ();
-       inline void __cb_shiftDown        ();
-       inline void __cb_setProgram       ();
-
-public:
-
-       class gButton *button;
-       class gChoice *program;
-       class gButton *bypass;
-       class gButton *shiftUp;
-       class gButton *shiftDown;
-       class gButton *remove;
-
-       gdPlugin(gdPluginList *gdp, class Plugin *p, int x, int y, int w);
-
-};
-
-#endif
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_pluginWindow.cpp b/src/gd_pluginWindow.cpp
deleted file mode 100644 (file)
index f9119c0..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginWindow
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-
-#include <FL/Fl_Scroll.H>
-#include "gd_pluginWindow.h"
-#include "pluginHost.h"
-#include "ge_mixed.h"
-#include "gui_utils.h"
-
-
-extern PluginHost G_PluginHost;
-
-
-Parameter::Parameter(int id, Plugin *p, int X, int Y, int W)
-       : Fl_Group(X,Y,W-24,20), id(id), pPlugin(p)
-{
-       begin();
-
-               label = new gBox(x(), y(), 60, 20);
-               char name[kVstMaxParamStrLen];
-               pPlugin->getParamName(id, name);
-               label->copy_label(name);
-               label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-
-               slider = new gSlider(label->x()+label->w()+8, y(), W-200, 20);
-               slider->value(pPlugin->getParam(id));
-               slider->callback(cb_setValue, (void *)this);
-
-               value = new gBox(slider->x()+slider->w()+8, y(), 100, 20);
-               char disp[kVstMaxParamStrLen];
-               char labl[kVstMaxParamStrLen];
-               char str [256];
-               pPlugin->getParamDisplay(id, disp);
-               pPlugin->getParamLabel(id, labl);
-               sprintf(str, "%s %s", disp, labl);
-               value->copy_label(str);
-               value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-               value->box(G_BOX);
-
-               resizable(slider);
-
-       end();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Parameter::cb_setValue(Fl_Widget *v, void *p)  { ((Parameter*)p)->__cb_setValue(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Parameter::__cb_setValue() {
-
-       pPlugin->setParam(id, slider->value());
-
-       char disp[256];
-       char labl[256];
-       char str [256];
-
-       pPlugin->getParamDisplay(id, disp);
-       pPlugin->getParamLabel(id, labl);
-       sprintf(str, "%s %s", disp, labl);
-
-       value->copy_label(str);
-       value->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdPluginWindow::gdPluginWindow(Plugin *pPlugin)
- : gWindow(400, 156), pPlugin(pPlugin) // 350
-{
-       set_non_modal();
-
-       gLiquidScroll *list = new gLiquidScroll(8, 8, w()-16, h()-16);
-       list->type(Fl_Scroll::VERTICAL_ALWAYS);
-       list->begin();
-
-       int numParams = pPlugin->getNumParams();
-       for (int i=0; i<numParams; i++)
-               new Parameter(i, pPlugin, list->x(), list->y()+(i*24), list->w());
-       list->end();
-
-       end();
-
-       char name[256];
-       pPlugin->getProduct(name);
-       if (strcmp(name, " ")==0)
-               pPlugin->getName(name);
-       label(name);
-
-       size_range(400, (24*1)+12);
-       resizable(list);
-
-       gu_setFavicon(this);
-       show();
-
-}
-
-
-gdPluginWindow::~gdPluginWindow() {}
-
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_pluginWindow.h b/src/gd_pluginWindow.h
deleted file mode 100644 (file)
index 03d49bf..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginWindow
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifdef WITH_VST
-
-#ifndef __GD_PLUGINWINDOW_H__
-#define __GD_PLUGINWINDOW_H__
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "ge_window.h"
-
-
-class gdPluginWindow : public gWindow {
-
-private:
-       class Plugin *pPlugin;
-
-public:
-       int id;
-
-       gdPluginWindow(Plugin *pPlugin);
-       ~gdPluginWindow();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class Parameter : public Fl_Group {
-
-private:
-       int   id;
-       class Plugin *pPlugin;
-
-       static void cb_setValue(Fl_Widget *v, void *p);
-       inline void __cb_setValue();
-
-public:
-       class gBox    *label;
-       class gSlider *slider;
-       class gBox    *value;
-
-       Parameter(int id, class Plugin *p, int x, int y, int w);
-};
-
-
-#endif
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_pluginWindowGUI.cpp b/src/gd_pluginWindowGUI.cpp
deleted file mode 100644 (file)
index 6fd0a07..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginWindowGUI
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-
-
-#include "gd_pluginWindowGUI.h"
-#include "pluginHost.h"
-#include "ge_mixed.h"
-#include "gui_utils.h"
-#include "log.h"
-
-
-extern PluginHost G_PluginHost;
-
-
-gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
- : gWindow(450, 300), pPlugin(pPlugin)
-{
-
-  /* some effects like to have us get their rect before opening them */
-
-  ERect *rect;
-       pPlugin->getRect(&rect);
-
-       gu_setFavicon(this);
-       set_non_modal();
-       resize(x(), y(), pPlugin->getGuiWidth(), pPlugin->getGuiWidth());
-       show();
-
-  gLog("[gdPluginWindowGUI] open window, w=%d h=%d\n",
-      pPlugin->getGuiWidth(), pPlugin->getGuiWidth());
-
-       /* Fl::check(): Waits until "something happens" and then returns. It's
-        * mandatory on linux, otherwise X can't find 'this' window. */
-
-       Fl::check();
-       pPlugin->openGui((void*)fl_xid(this));
-
-       char name[256];
-       pPlugin->getProduct(name);
-       copy_label(name);
-
-       /* add a pointer to this window to plugin */
-
-       pPlugin->window = this;
-
-       pPlugin->idle();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdPluginWindowGUI::~gdPluginWindowGUI() {
-       pPlugin->closeGui();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-#if defined(__APPLE__)
-
-
-pascal OSStatus gdPluginWindowGUImac::windowHandler(EventHandlerCallRef ehc, EventRef e, void *data) {
-       return ((gdPluginWindowGUImac*)data)->__wh(ehc, e);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-pascal OSStatus gdPluginWindowGUImac::__wh(EventHandlerCallRef inHandlerCallRef, EventRef inEvent) {
-       OSStatus result   = eventNotHandledErr;     // let the Carbon Event Manager close the window
-       UInt32 eventClass = GetEventClass(inEvent);
-       UInt32 eventKind  = GetEventKind(inEvent);
-
-       switch (eventClass)     {
-               case kEventClassWindow: {
-                       switch (eventKind) {
-                               case kEventWindowClose: {
-                                       gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClose for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow);
-                                       show();
-                                       break;
-                               }
-                               case kEventWindowClosed: {
-                                       gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClosed for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow);
-                                       open = false;
-                                       result = noErr;
-                                       break;
-                               }
-                       }
-                       break;
-               }
-       }
-       return result;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdPluginWindowGUImac::gdPluginWindowGUImac(Plugin *pPlugin)
- : gWindow(450, 300), pPlugin(pPlugin), carbonWindow(NULL)
-{
-
-  /* some effects like to have us get their rect before opening them */
-
-  ERect *rect;
-       pPlugin->getRect(&rect);
-
-       /* window initialization */
-
-       Rect wRect;
-
-       wRect.top    = rect->top;
-       wRect.left   = rect->left;
-       wRect.bottom = rect->bottom;
-       wRect.right  = rect->right;
-
-  int winclass = kDocumentWindowClass;
-  int winattr  = kWindowStandardHandlerAttribute |
-                 kWindowCloseBoxAttribute        |
-                 kWindowCompositingAttribute     |
-                 kWindowAsyncDragAttribute;
-
-  // winattr &= GetAvailableWindowAttributes(winclass);        // make sure that the window will open
-
-  OSStatus status = CreateNewWindow(winclass, winattr, &wRect, &carbonWindow);
-       if (status != noErr)    {
-               gLog("[pluginWindowMac] Unable to create window! Status=%d\n", (int) status);
-               return;
-       }
-       else
-               gLog("[pluginWindowMac] created window=%p\n", (void*)carbonWindow);
-
-       /* install event handler, called when window is closed */
-
-       static EventTypeSpec eventTypes[] = {
-               { kEventClassWindow, kEventWindowClose },
-               { kEventClassWindow, kEventWindowClosed }
-       };
-       InstallWindowEventHandler(carbonWindow, windowHandler, GetEventTypeCount(eventTypes), eventTypes, this, NULL);
-
-       /* open window, center it, show it and start the handler */
-
-       pPlugin->openGui((void*)carbonWindow);
-       RepositionWindow(carbonWindow, NULL, kWindowCenterOnMainScreen);
-       ShowWindow(carbonWindow);
-       open = true;
-}
-
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdPluginWindowGUImac::~gdPluginWindowGUImac() {
-       gLog("[pluginWindowMac] [[[ destructor ]]] gWindow=%p deleted, window=%p deleted\n", (void*)this, (void*)carbonWindow);
-       pPlugin->closeGui();
-       if (open)
-               DisposeWindow(carbonWindow);
-}
-
-#endif
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_pluginWindowGUI.h b/src/gd_pluginWindowGUI.h
deleted file mode 100644 (file)
index 1675e73..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginWindowGUI
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-
-
-#ifndef __GD_PLUGINWINDOW_GUI_H__
-#define __GD_PLUGINWINDOW_GUI_H__
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "ge_window.h"
-#if defined(__APPLE__)
-       #include <Carbon/Carbon.h>
-#endif
-
-
-class gdPluginWindowGUI : public gWindow {
-private:
-
-       class Plugin *pPlugin;
-
-public:
-
-       gdPluginWindowGUI(Plugin *pPlugin);
-       ~gdPluginWindowGUI();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-#if defined(__APPLE__)
-
-class gdPluginWindowGUImac : public gWindow {
-
-private:
-
-       static pascal OSStatus windowHandler(EventHandlerCallRef ehc, EventRef e, void *data);
-       inline pascal OSStatus __wh(EventHandlerCallRef ehc, EventRef e);
-
-       class Plugin *pPlugin;
-       WindowRef carbonWindow;
-       bool open;
-
-public:
-
-       gdPluginWindowGUImac(Plugin *pPlugin);
-       ~gdPluginWindowGUImac();
-};
-
-#endif
-
-
-#endif // include guard
-
-#endif // #ifdef WITH_VST
diff --git a/src/gd_warnings.cpp b/src/gd_warnings.cpp
deleted file mode 100644 (file)
index 31a5dbc..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_warnings
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gd_warnings.h"
-
-
-void gdAlert(const char *c) {
-       Fl_Window *modal = new Fl_Window(
-                       (Fl::w() / 2) - 150,
-                       (Fl::h() / 2) - 47,
-                       300, 90, "Alert");
-       modal->set_modal();
-       modal->begin();
-               gBox *box = new gBox(10, 10, 280, 40, c);
-               gClick *b = new gClick(210, 60, 80, 20, "Close");
-       modal->end();
-       box->labelsize(11);
-       b->callback(__cb_window_closer, (void *)modal);
-       b->shortcut(FL_Enter);
-       gu_setFavicon(modal);
-       modal->show();
-}
-
-
-int gdConfirmWin(const char *title, const char *msg) {
-       Fl_Window *win = new Fl_Window(
-                       (Fl::w() / 2) - 150,
-                       (Fl::h() / 2) - 47,
-                       300, 90, title);
-       win->set_modal();
-       win->begin();
-               new gBox(10, 10, 280, 40, msg);
-               gClick *ok = new gClick(212, 62, 80, 20, "Ok");
-               gClick *ko = new gClick(124, 62, 80, 20, "Cancel");
-       win->end();
-       ok->shortcut(FL_Enter);
-       gu_setFavicon(win);
-       win->show();
-
-       /* no callbacks here. readqueue() check the event stack. */
-
-       int r = 0;
-       while (true) {
-               Fl_Widget *o = Fl::readqueue();
-               if (!o) Fl::wait();
-               else if (o == ok) {r = 1; break;}
-               else if (o == ko) {r = 0; break;}
-       }
-       //delete win;
-       win->hide();
-       return r;
-}
diff --git a/src/gd_warnings.h b/src/gd_warnings.h
deleted file mode 100644 (file)
index ca9c633..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_warnings
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GD_WARNINGS_H
-#define GD_WARNINGS_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include <FL/Fl_Box.H>
-#include "ge_mixed.h"
-#include "gui_utils.h"
-
-
-void gdAlert(const char *c);
-
-int  gdConfirmWin(const char *title, const char *msg);
-
-#endif
diff --git a/src/ge_actionChannel.cpp b/src/ge_actionChannel.cpp
deleted file mode 100644 (file)
index a98d394..0000000
+++ /dev/null
@@ -1,676 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionChannel
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "glue.h"
-#include "ge_actionChannel.h"
-#include "gd_mainWindow.h"
-#include "gd_actionEditor.h"
-#include "gg_keyboard.h"
-#include "conf.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "log.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-extern Conf             G_Conf;
-
-
-/* ------------------------------------------------------------------ */
-
-
-gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch)
- : gActionWidget(x, y, 200, 40, pParent), ch(ch), selected(NULL)
-{
-       size(pParent->totalWidth, h());
-
-       /* add actions when the window opens. Their position is zoom-based;
-        * each frame is / 2 because we don't care about stereo infos. */
-
-       for (unsigned i=0; i<recorder::frames.size; i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
-
-                       recorder::action *ra = recorder::global.at(i).at(j);
-
-                       if (ra->chan == pParent->chan->index) {
-
-                               /* don't show actions > than the grey area */
-
-                               if (recorder::frames.at(i) > G_Mixer.totalFrames)
-                                       continue;
-
-                               /* skip the killchan actions in a singlepress channel. They cannot be recorded
-                                * in such mode, but they can exist if you change from another mode to singlepress */
-
-                               if (ra->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS)
-                                       continue;
-
-                               /* also filter out ACTION_KEYREL: it's up to gAction to find the other piece
-                                * (namely frame_b) */
-
-                               if (ra->type & (ACTION_KEYPRESS | ACTION_KILLCHAN))     {
-                                       int ax = x+(ra->frame/pParent->zoom);
-                                       gAction *a = new gAction(
-                                                       ax,           // x
-                                                       y+4,          // y
-                                                       h()-8,        // h
-                                                       ra->frame,        // frame_a
-                                                       i,            // n. of recordings
-                                                       pParent,      // pointer to the pParent window
-                                                       ch,           // pointer to SampleChannel
-                                                       false,        // record = false: don't record it, we are just displaying it!
-                                                       ra->type);    // type of action
-                                       add(a);
-                               }
-                       }
-               }
-       }
-       end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gAction *gActionChannel::getSelectedAction() {
-       for (int i=0; i<children(); i++) {
-               int action_x  = ((gAction*)child(i))->x();
-               int action_w  = ((gAction*)child(i))->w();
-               if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w)
-                       return (gAction*)child(i);
-       }
-       return NULL;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gActionChannel::updateActions() {
-
-       /* when zooming, don't delete and re-add actions, just MOVE them. This
-        * function shifts the action by a zoom factor. Those singlepress are
-        * stretched, as well */
-
-       gAction *a;
-       for (int i=0; i<children(); i++) {
-
-               a = (gAction*)child(i);
-               int newX = x() + (a->frame_a / pParent->zoom);
-
-               if (ch->mode == SINGLE_PRESS) {
-                       int newW = ((a->frame_b - a->frame_a) / pParent->zoom);
-                       if (newW < gAction::MIN_WIDTH)
-                               newW = gAction::MIN_WIDTH;
-                       a->resize(newX, a->y(), newW, a->h());
-               }
-               else
-                       a->resize(newX, a->y(), gAction::MIN_WIDTH, a->h());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gActionChannel::draw() {
-
-       /* draw basic boundaries (+ beat bars) and hide the unused area. Then
-        * draw the children (the actions) */
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       if (active())
-               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
-       else
-               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
-
-       draw_children();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gActionChannel::handle(int e) {
-
-       int ret = Fl_Group::handle(e);
-
-       /* do nothing if the widget is deactivated. It could happen for loopmode
-        * channels */
-
-       if (!active())
-               return 1;
-
-       switch (e) {
-
-               case FL_DRAG: {
-                       if (selected != NULL) {   // if you don't drag an empty area
-
-                               /* if onLeftEdge o onRightEdge are true it means that you're resizing
-                                * an action. Otherwise move the widget. */
-
-                               if (selected->onLeftEdge || selected->onRightEdge) {
-
-                                       /* some checks: a) cannot resize an action < N pixels, b) no beyond zero,
-                                        * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */
-
-                                       if (selected->onRightEdge) {
-
-                                               int aw = Fl::event_x()-selected->x();
-                                               int ah = selected->h();
-
-                                               if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH)
-                                                       aw = gAction::MIN_WIDTH;
-                                               else
-                                               if (Fl::event_x() > pParent->coverX)
-                                                       aw = pParent->coverX-selected->x();
-
-                                               selected->size(aw, ah);
-                                       }
-                                       else {
-
-                                               int ax = Fl::event_x();
-                                               int ay = selected->y();
-                                               int aw = selected->x()-Fl::event_x()+selected->w();
-                                               int ah = selected->h();
-
-                                               if (Fl::event_x() < x()) {
-                                                       ax = x();
-                                                       aw = selected->w()+selected->x()-x();
-                                               }
-                                               else
-                                               if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) {
-                                                       ax = selected->x()+selected->w()-gAction::MIN_WIDTH;
-                                                       aw = gAction::MIN_WIDTH;
-                                               }
-                                               selected->resize(ax, ay, aw, ah);
-                                       }
-                               }
-
-                               /* move the widget around */
-
-                               else {
-                                       int real_x = Fl::event_x() - actionPickPoint;
-                                       if (real_x < x())                                  // don't go beyond the left border
-                                               selected->position(x(), selected->y());
-                                       else
-                                       if (real_x+selected->w() > pParent->coverX+x())         // don't go beyond the right border
-                                               selected->position(pParent->coverX+x()-selected->w(), selected->y());
-                                       else {
-                                               if (pParent->gridTool->isOn()) {
-                                                       int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1;
-                                                       selected->position(snpx, selected->y());
-                                               }
-                                               else
-                                                       selected->position(real_x, selected->y());
-                                       }
-                               }
-                               redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH:   {
-
-                       if (Fl::event_button1()) {
-
-                               /* avoid at all costs two overlapping actions. We use 'selected' because
-                                * the selected action can be reused in FL_DRAG, in case you want to move
-                                * it. */
-
-                               selected = getSelectedAction();
-
-                               if (selected == NULL) {
-
-                                       /* avoid click on grey area */
-
-                                       if (Fl::event_x() >= pParent->coverX) {
-                                               ret = 1;
-                                               break;
-                                       }
-
-                                       /* snap function, if enabled */
-
-                                       int ax = Fl::event_x();
-                                       int fx = (ax - x()) * pParent->zoom;
-                                       if (pParent->gridTool->isOn()) {
-                                               ax = pParent->gridTool->getSnapPoint(ax-x()) + x() -1;
-                                               fx = pParent->gridTool->getSnapFrame(ax-x());
-
-                                               /* with snap=on an action can fall onto another */
-
-                                               if (actionCollides(fx)) {
-                                                       ret = 1;
-                                                       break;
-                                               }
-                                       }
-
-                                       gAction *a = new gAction(
-                                                       ax,                                   // x
-                                                       y()+4,                                // y
-                                                       h()-8,                                // h
-                                                       fx,                                                                                                                                             // frame_a
-                                                       recorder::frames.size-1,              // n. of actions recorded
-                                                       pParent,                              // pParent window pointer
-                                                       ch,                                   // pointer to SampleChannel
-                                                       true,                                 // record = true: record it!
-                                                       pParent->getActionType());            // type of action
-                                       add(a);
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); // mainWindow update
-                                       redraw();
-                                       ret = 1;
-                               }
-                               else {
-                                       actionOriginalX = selected->x();
-                                       actionOriginalW = selected->w();
-                                       actionPickPoint = Fl::event_x() - selected->x();
-                                       ret = 1;   // for dragging
-                               }
-                       }
-                       else
-                       if (Fl::event_button3()) {
-                               gAction *a = getSelectedAction();
-                               if (a != NULL) {
-                                       a->delAction();
-                                       remove(a);
-                                       delete a;
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel);
-                                       redraw();
-                                       ret = 1;
-                               }
-                       }
-                       break;
-               }
-               case FL_RELEASE: {
-
-                       if (selected == NULL) {
-                               ret = 1;
-                               break;
-                       }
-
-                       /* noChanges = true when you click on an action without doing anything
-                        * (dragging or moving it). */
-
-                       bool noChanges = false;
-                       if (actionOriginalX == selected->x())
-                               noChanges = true;
-                       if (ch->mode == SINGLE_PRESS &&
-                                       actionOriginalX+actionOriginalW != selected->x()+selected->w())
-                               noChanges = false;
-
-                       if (noChanges) {
-                               ret = 1;
-                               selected = NULL;
-                               break;
-                       }
-
-                       /* step 1: check if the action doesn't overlap with another one.
-                        * In case of overlap the moved action returns to the original X
-                        * value ("actionOriginalX"). */
-
-                       bool overlap = false;
-                       for (int i=0; i<children() && !overlap; i++) {
-
-                               /* never check against itself. */
-
-                               if ((gAction*)child(i) == selected)
-                                       continue;
-
-                               int action_x  = ((gAction*)child(i))->x();
-                               int action_w  = ((gAction*)child(i))->w();
-                               if (ch->mode == SINGLE_PRESS) {
-
-                                       /* when 2 segments overlap?
-                                        * start = the highest value between the two starting points
-                                        * end   = the lowest value between the two ending points
-                                        * if start < end then there's an overlap of end-start pixels. */
-
-                                        int start = action_x >= selected->x() ? action_x : selected->x();
-                                        int end   = action_x+action_w < selected->x()+selected->w() ? action_x+action_w : selected->x()+selected->w();
-                                        if (start < end) {
-                                               selected->resize(actionOriginalX, selected->y(), actionOriginalW, selected->h());
-                                               redraw();
-                                               overlap = true;   // one overlap: stop checking
-                                       }
-                               }
-                               else {
-                                       if (selected->x() == action_x) {
-                                               selected->position(actionOriginalX, selected->y());
-                                               redraw();
-                                               overlap = true;   // one overlap: stop checking
-                                       }
-                               }
-                       }
-
-                       /* step 2: no overlap? then update the coordinates of the action, ie
-                        * delete the previous rec and create a new one.
-                        * Anyway the selected action becomes NULL, because when you release
-                        * the mouse button the dragging process ends. */
-
-                       if (!overlap) {
-                               if (pParent->gridTool->isOn()) {
-                                       int f = pParent->gridTool->getSnapFrame(selected->absx());
-                                       selected->moveAction(f);
-                               }
-                               else
-                                       selected->moveAction();
-                       }
-                       selected = NULL;
-                       ret = 1;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gActionChannel::actionCollides(int frame) {
-
-       /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't
-        * overlap the head (frame) of the new one. First the general case, yet. */
-
-       bool collision = false;
-
-       for (int i=0; i<children() && !collision; i++)
-               if ( ((gAction*)child(i))->frame_a == frame)
-                       collision = true;
-
-       if (ch->mode == SINGLE_PRESS) {
-               for (int i=0; i<children() && !collision; i++) {
-                       gAction *c = ((gAction*)child(i));
-                       if (frame <= c->frame_b && frame >= c->frame_a)
-                               collision = true;
-               }
-       }
-
-       return collision;
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-const int gAction::MIN_WIDTH = 8;
-
-
-/* ------------------------------------------------------------------ */
-
-
-/** TODO - index is useless?
- *  TODO - pass a record::action pointer and let gAction compute values */
-
-gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEditor *parent, SampleChannel *ch, bool record, char type)
-: Fl_Box     (X, Y, MIN_WIDTH, H),
-  selected   (false),
-  index      (index),
-  parent     (parent),
-  ch         (ch),
-  type       (type),
-  frame_a    (frame_a),
-  onRightEdge(false),
-  onLeftEdge (false)
-{
-       /* bool 'record' defines how to understand the action.
-        * record = false: don't record it, just show it. It happens when you
-        * open the editor with some actions to be shown.
-        *
-        * record = true: record it AND show it. It happens when you click on
-        * an empty area in order to add a new actions. First you record it
-        * (addAction()) then you show it (FLTK::Draw()) */
-
-       if (record)
-               addAction();
-
-       /* in order to show a singlepress action we must compute the frame_b. We
-        * do that after the possible recording, otherwise we don't know which
-        * key_release is associated. */
-
-       if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) {
-               recorder::action *a2 = NULL;
-               recorder::getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2);
-               if (a2) {
-                       frame_b = a2->frame;
-                       w((frame_b - frame_a)/parent->zoom);
-               }
-               else
-                       gLog("[gActionChannel] frame_b not found! [%d:???]\n", frame_a);
-
-       /* a singlepress action narrower than 8 pixel is useless. So check it.
-        * Warning: if an action is 8 px narrow, it has no body space to drag
-        * it. It's up to the user to zoom in and drag it. */
-
-               if (w() < MIN_WIDTH)
-                       size(MIN_WIDTH, h());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gAction::draw() {
-
-       int color;
-       if (selected)  /// && gActionChannel !disabled
-               color = COLOR_BD_1;
-       else
-               color = COLOR_BG_2;
-
-       if (ch->mode == SINGLE_PRESS) {
-               fl_rectf(x(), y(), w(), h(), (Fl_Color) color);
-       }
-       else {
-               if (type == ACTION_KILLCHAN)
-                       fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-               else {
-                       fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-                       if (type == ACTION_KEYPRESS)
-                               fl_rectf(x()+3, y()+h()-11, 2, 8, COLOR_BD_0);
-                       else
-                       if  (type == ACTION_KEYREL)
-                               fl_rectf(x()+3, y()+3, 2, 8, COLOR_BD_0);
-               }
-       }
-
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gAction::handle(int e) {
-
-       /* ret = 0 sends the event to the parent window. */
-
-       int ret = 0;
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       selected = true;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-               case FL_LEAVE: {
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       selected = false;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-               case FL_MOVE: {
-
-                       /* handling of the two margins, left & right. 4 pixels are good enough */
-
-                       if (ch->mode == SINGLE_PRESS) {
-                               onLeftEdge  = false;
-                               onRightEdge = false;
-                               if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
-                                       onLeftEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                               if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
-                                       onRightEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       }
-               }
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gAction::addAction() {
-
-       /* always check frame parity */
-
-       if (frame_a % 2 != 0)
-               frame_a++;
-
-       /* anatomy of an action
-        * ____[#######]_____ (a) is the left margin, ACTION_KEYPRESS. (b) is
-        *     a       b      the right margin, the ACTION_KEYREL. This is the
-        * theory behind the singleshot.press actions; for any other kind the
-        * (b) is just a graphical and meaningless point. */
-
-       if (ch->mode == SINGLE_PRESS) {
-               recorder::rec(parent->chan->index, ACTION_KEYPRESS, frame_a);
-               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_a+4096);
-               //gLog("action added, [%d, %d]\n", frame_a, frame_a+4096);
-       }
-       else {
-               recorder::rec(parent->chan->index, parent->getActionType(), frame_a);
-               //gLog("action added, [%d]\n", frame_a);
-       }
-
-       recorder::sortActions();
-
-       index++; // important!
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gAction::delAction() {
-
-       /* if SINGLE_PRESS you must delete both the keypress and the keyrelease
-        * actions. */
-
-       if (ch->mode == SINGLE_PRESS) {
-               recorder::deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false);
-               recorder::deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false);
-       }
-       else
-               recorder::deleteAction(parent->chan->index, frame_a, type, false);
-
-       /* restore the initial cursor shape, in case you delete an action and
-        * the double arrow (for resizing) is displayed */
-
-       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gAction::moveAction(int frame_a) {
-
-       /* easy one: delete previous action and record the new ones. As usual,
-        * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame
-        * value. */
-
-       delAction();
-
-       if (frame_a != -1)
-               this->frame_a = frame_a;
-       else
-               this->frame_a = xToFrame_a();
-
-
-       /* always check frame parity */
-
-       if (this->frame_a % 2 != 0)
-               this->frame_a++;
-
-       recorder::rec(parent->chan->index, type, this->frame_a);
-
-       if (ch->mode == SINGLE_PRESS) {
-               frame_b = xToFrame_b();
-               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_b);
-       }
-
-       recorder::sortActions();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gAction::absx() {
-       return x() - parent->ac->x();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gAction::xToFrame_a() {
-       return (absx()) * parent->zoom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gAction::xToFrame_b() {
-       return (absx() + w()) * parent->zoom;
-}
diff --git a/src/ge_actionChannel.h b/src/ge_actionChannel.h
deleted file mode 100644 (file)
index bd0fe24..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionChannel
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GE_ACTIONCHANNEL_H
-#define GE_ACTIONCHANNEL_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Box.H>
-#include "ge_actionWidget.h"
-#include "gui_utils.h"
-#include "mixer.h"
-#include "recorder.h"
-
-
-class gAction : public Fl_Box {
-
-private:
-
-       bool                  selected;
-       unsigned              index;
-  class gdActionEditor *parent;   // pointer to parent (gActionEditor)
-       class SampleChannel  *ch;
-  char                  type;     // type of action
-
-public:
-       gAction(int x, int y, int h, int frame_a, unsigned index,
-                                 gdActionEditor *parent, class SampleChannel *ch, bool record,
-                           char type);
-       void draw();
-       int  handle(int e);
-       void addAction();
-       void delAction();
-
-       /* moveAction
-        * shift the action on the x-axis and update Recorder. If frame_a != -1
-        * use the new frame in input (used while snapping) */
-
-       void moveAction(int frame_a=-1);
-
-       /* absx
-        * x() is relative to scrolling position. absx() returns the absolute
-        * x value of the action, from the leftmost edge. */
-
-       int  absx();
-
-       /* xToFrame_a,b
-        * return the real frames of x() position */
-
-       int xToFrame_a();
-       int xToFrame_b();
-
-       int frame_a;  // initial frame (KEYPRESS for singlemode.press)
-       int frame_b;  // terminal frame (KEYREL for singlemode.press, null for others)
-
-       bool onRightEdge;
-       bool onLeftEdge;
-
-       static const int MIN_WIDTH;
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gActionChannel : public gActionWidget {
-
-private:
-
-       class SampleChannel *ch;
-
-       /* getSelectedAction
-        * get the action under the mouse. NULL if nothing found. */
-
-       gAction *getSelectedAction();
-
-       /* selected
-        * pointer to the selected action. Useful when dragging around. */
-
-       gAction *selected;
-
-       /* actionOriginalX, actionOriginalW
-        * x and w of the action, when moved. Useful for checking if the action
-        * overlaps another one: in that case the moved action returns to
-        * actionOriginalX (and to actionOriginalW if resized). */
-
-       int actionOriginalX;
-       int actionOriginalW;
-
-       /* actionPickPoint
-        * the precise x point in which the action has been picked with the mouse,
-        * before a dragging action. */
-
-       int actionPickPoint;
-
-
-       /* actionCollides
-        * true if an action collides with another. Used while adding new points
-        * with snap active.*/
-
-       bool actionCollides(int frame);
-
-public:
-       gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch);
-       void draw();
-       int  handle(int e);
-       void updateActions();
-};
-
-
-#endif
diff --git a/src/ge_actionWidget.cpp b/src/ge_actionWidget.cpp
deleted file mode 100644 (file)
index a06eab9..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionWidget
- *
- * pParent class of any widget inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "ge_actionWidget.h"
-#include "gd_actionEditor.h"
-#include "mixer.h"
-#include "ge_mixed.h"
-
-
-extern Mixer G_Mixer;
-
-
-gActionWidget::gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent)
-       :       Fl_Group(x, y, w, h), pParent(pParent) {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gActionWidget::~gActionWidget() {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gActionWidget::baseDraw(bool clear) {
-
-       /* clear the screen */
-
-       if (clear)
-               fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
-
-       /* draw the container */
-
-       fl_color(COLOR_BD_0);
-       fl_rect(x(), y(), w(), h());
-
-       /* grid drawing, if > 1 */
-
-       if (pParent->gridTool->getValue() > 1) {
-
-               fl_color(fl_rgb_color(54, 54, 54));
-               fl_line_style(FL_DASH, 0, NULL);
-
-               for (int i=0; i<(int) pParent->gridTool->points.size; i++) {
-                       int px = pParent->gridTool->points.at(i)+x()-1;
-                       fl_line(px, y()+1, px, y()+h()-2);
-               }
-               fl_line_style(0);
-       }
-
-       /* bars and beats drawing */
-
-       fl_color(COLOR_BD_0);
-       for (int i=0; i<(int) pParent->gridTool->beats.size; i++) {
-               int px = pParent->gridTool->beats.at(i)+x()-1;
-               fl_line(px, y()+1, px, y()+h()-2);
-       }
-
-       fl_color(COLOR_BG_2);
-       for (int i=0; i<(int) pParent->gridTool->bars.size; i++) {
-               int px = pParent->gridTool->bars.at(i)+x()-1;
-               fl_line(px, y()+1, px, y()+h()-2);
-       }
-
-       /* cover unused area. Avoid drawing cover if width == 0 (i.e. beats
-        * are 32) */
-
-       int coverWidth = pParent->totalWidth-pParent->coverX;
-       if (coverWidth != 0)
-               fl_rectf(pParent->coverX+x(), y()+1, coverWidth, h()-2, COLOR_BG_1);
-}
diff --git a/src/ge_actionWidget.h b/src/ge_actionWidget.h
deleted file mode 100644 (file)
index 554f569..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionWidget
- *
- * parent class of any widget inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __GE_ACTIONWIDGET_H__
-#define __GE_ACTIONWIDGET_H__
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "const.h"
-
-
-class gActionWidget : public Fl_Group {
-
-protected:
-       class gdActionEditor *pParent;
-       void  baseDraw(bool clear=true);
-
-public:
-       virtual void updateActions() = 0;
-
-       gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent);
-       ~gActionWidget();
-};
-
-#endif
diff --git a/src/ge_browser.cpp b/src/ge_browser.cpp
deleted file mode 100644 (file)
index 15f6836..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_browser
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <limits.h>
-#include "ge_browser.h"
-#include "const.h"
-#include "utils.h"
-#include "log.h"
-
-
-gBrowser::gBrowser(int x, int y, int w, int h, const char *L)
- : Fl_Hold_Browser(x, y, w, h, L)
-{
-       box(G_BOX);
-       textsize(11);
-       textcolor(COLOR_TEXT_0);
-       selection_color(COLOR_BG_1);
-       color(COLOR_BG_0);
-
-       this->scrollbar.color(COLOR_BG_0);
-       this->scrollbar.selection_color(COLOR_BG_1);
-       this->scrollbar.labelcolor(COLOR_BD_1);
-       this->scrollbar.slider(G_BOX);
-
-       this->hscrollbar.color(COLOR_BG_0);
-       this->hscrollbar.selection_color(COLOR_BG_1);
-       this->hscrollbar.labelcolor(COLOR_BD_1);
-       this->hscrollbar.slider(G_BOX);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gBrowser::~gBrowser() {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gBrowser::init(const char *init_path) {
-
-       gLog("[gBrowser] init path = '%s'\n", init_path);
-
-       if (init_path == NULL || !gIsDir(init_path)) {
-#if defined(__linux__) || defined(__APPLE__)
-               path_obj->value("/home");
-#elif defined(_WIN32)
-
-               /* SHGetFolderPath is deprecated. We should use SHGetKnownFolderPath
-                * but that would break compatibility with XP. On Vista, GetFolderPath
-                * is a wrapper of GetKnownFolderPath, so no problem. */
-
-               char winRoot[1024];
-               SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, winRoot); // si parte dal Desktop
-               path_obj->value(winRoot);
-#endif
-               gLog("[gBrowser] init_path null or invalid, using default\n");
-       }
-       else
-               path_obj->value(init_path);
-
-       refresh();
-       sort();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gBrowser::refresh() {
-  DIR *dp;
-  struct dirent *ep;
-  dp = opendir(path_obj->value());
-  if (dp != NULL) {
-               while ((ep = readdir(dp))) {
-
-                       /* skip:
-                        * - "." e ".."
-                        * - hidden files */
-
-                       if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
-                               if (ep->d_name[0] != '.') {
-
-                                       /* is it a folder? add square brackets. Is it a file? Append
-                                        * a '/' (on Windows seems useless, though) */
-
-                                       std::string file = path_obj->value();
-                                       file.insert(file.size(), gGetSlash());
-                                       file += ep->d_name;
-
-                                       if (gIsDir(file.c_str())) {
-                                               char name[PATH_MAX];
-                                               sprintf(name, "@b[%s]", ep->d_name);
-                                               add(name);
-                                       }
-                                       else
-                                       if (gIsProject(file.c_str())) {
-                                               char name[PATH_MAX];
-                                               sprintf(name, "@i@b%s", ep->d_name);
-                                               add(name);
-                                       }
-                                       else
-                                               add(ep->d_name);
-                               }
-                       }
-               }
-               closedir(dp);
-  }
-  else
-    gLog("[gBrowser] Couldn't open the directory '%s'\n", path_obj->value());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gBrowser::sort() {
-       for (int t=1; t<=size(); t++)
-               for (int r=t+1; r<=size(); r++)
-                       if (strcmp(text(t), text(r)) > 0)
-                               swap(t,r);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gBrowser::up_dir() {
-
-       /* updir = remove last folder from the path. Start from strlen(-1) to
-        * skip the trailing slash */
-
-       int i = strlen(path_obj->value())-1;
-
-       /* on Windows an updir from the path "X:\" (3 chars long) must redirect
-        * to the list of available devices. */
-
-#if defined(_WIN32)
-       if (i <= 3 || !strcmp(path_obj->value(), "All drives")) {
-               path_obj->value("All drives");
-               showDrives();
-               return;
-       }
-       else {
-               while (i >= 0) {
-                       if (path_obj->value()[i] == '\\')
-                               break;
-                       i--;
-               }
-
-               /* delete the last part of the string, from i to len-i, ie everything
-                * after the "/" */
-
-               std::string tmp = path_obj->value();
-               tmp.erase(i, tmp.size()-i);
-
-               /* if tmp.size == 2 we have something like 'C:'. Add a trailing
-                * slash */
-
-               if (tmp.size() == 2)
-                       tmp += "\\";
-
-               path_obj->value(tmp.c_str());
-               refresh();
-       }
-#elif defined(__linux__) || defined (__APPLE__)
-       while (i >= 0) {
-               if (path_obj->value()[i] == '/')
-                       break;
-               i--;
-       }
-
-       /* i == 0 means '/', the root dir. It's meaningless to go updir */
-
-       if (i==0)
-               path_obj->value("/");
-       else {
-
-               /* delete the last part of the string, from i to len-i, ie everything
-                * after the "/" */
-
-               std::string tmp = path_obj->value();
-               tmp.erase(i, tmp.size()-i);
-               path_obj->value(tmp.c_str());
-       }
-       refresh();
-#endif
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gBrowser::down_dir(const char *path) {
-       path_obj->value(path);
-       refresh();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-const char *gBrowser::get_selected_item() {
-
-       /* click on an empty line */
-
-       if (text(value()) == NULL)
-               return NULL;
-
-       selected_item = text(value());
-
-       /* @ = formatting marks.
-        * @b = bold, i.e. a directory. Erease '@b[' and ']' */
-
-       if (selected_item[0] == '@') {
-               if (selected_item[1] == 'b') {
-                       selected_item.erase(0, 3);
-                       selected_item.erase(selected_item.size()-1, 1);
-               }
-               else
-               if (selected_item[1] == 'i')
-                       selected_item.erase(0, 4);
-       }
-
-#if defined(__linux__) || defined(__APPLE__)
-
-       /* add path to file name, to get an absolute path. Avoid double
-        * slashes like '//' */
-
-       if (strcmp("/", path_obj->value()))
-               selected_item.insert(0, "/");
-
-       selected_item.insert(0, path_obj->value());
-       return selected_item.c_str();
-#elif defined(_WIN32)
-
-       /* if path is 'All drives' we are in the devices list and the user
-        * has clicked on a device such as 'X:\' */
-
-       if (strcmp(path_obj->value(), "All drives") == 0)
-                       return selected_item.c_str();
-       else {
-
-               /* add '\' if the path is like 'X:\' */
-
-               if (strlen(path_obj->value()) > 3) /// shouln't it be == 3?
-                       selected_item.insert(0, "\\");
-
-               selected_item.insert(0, path_obj->value());
-               return selected_item.c_str();
-       }
-#endif
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-#ifdef _WIN32
-void gBrowser::showDrives() {
-
-       /* GetLogicalDriveStrings fills drives like that:
-        *
-        * a:\[null]b:\[null]c:\[null]...[null][null]
-        *
-        * where [null] stands for \0. */
-
-       char drives[64];
-       char *i = drives;               // pointer to 0th element in drives
-       GetLogicalDriveStrings(64, drives);
-
-       /* code stolen from the web, still unknown. (Jan 09, 2012). */
-
-       while (*i) {
-               add(i);
-               i = &i[strlen(i) + 1];
-       }
-}
-
-#endif
diff --git a/src/ge_browser.h b/src/ge_browser.h
deleted file mode 100644 (file)
index 8445319..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_browser
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GE_BROWSER_H
-#define GE_BROWSER_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Hold_Browser.H>
-#include <string>
-#include "ge_mixed.h"
-
-class gBrowser : public Fl_Hold_Browser {
-public:
-       gBrowser(int x, int y, int w, int h, const char *L=0);
-       ~gBrowser();
-       void init(const char *init_path=NULL);
-       void refresh();
-       void sort();
-       void up_dir();
-       void down_dir(const char *path);
-       const char *get_selected_item();
-
-       /* path_obj
-        * the actual path*/
-
-       class gInput *path_obj;
-
-       /* selected_item
-        * choosen item */
-
-       std::string selected_item;
-
-#ifdef _WIN32
-private:
-
-       /* showDrives [WIN32 only]
-        * lists all the available drivers */
-
-       void showDrives();
-#endif
-};
-
-#endif
diff --git a/src/ge_channel.cpp b/src/ge_channel.cpp
deleted file mode 100644 (file)
index 71cfb38..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channel
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "gd_mainWindow.h"
-#include "gd_keyGrabber.h"
-#include "gd_midiInput.h"
-#include "gd_editor.h"
-#include "gd_actionEditor.h"
-#include "gd_warnings.h"
-#include "gd_browser.h"
-#include "gd_midiOutput.h"
-#include "gg_keyboard.h"
-#include "pluginHost.h"
-#include "mixer.h"
-#include "conf.h"
-#include "patch.h"
-#include "graphics.h"
-#include "channel.h"
-#include "wave.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "glue.h"
-#include "gui_utils.h"
-
-#ifdef WITH_VST
-#include "gd_pluginList.h"
-#endif
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch                G_Patch;
-extern gdMainWindow *mainWin;
-
-
-gChannel::gChannel(int X, int Y, int W, int H, int type)
- : Fl_Group(X, Y, W, H, NULL), type(type) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gChannel::getColumnIndex()
-{
-       return ((gColumn*)parent())->getIndex();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannel::blink()
-{
-       if (gu_getBlinker() > 6) {
-               mainButton->bgColor0 = COLOR_BG_2;
-               mainButton->bdColor  = COLOR_BD_1;
-               mainButton->txtColor = COLOR_TEXT_1;
-       }
-       else {
-               mainButton->bgColor0 = COLOR_BG_0;
-               mainButton->bdColor  = COLOR_BD_0;
-               mainButton->txtColor = COLOR_TEXT_0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannel::setColorsByStatus(int playStatus, int recStatus)
-{
-  switch (playStatus) {
-    case STATUS_OFF:
-               mainButton->bgColor0 = COLOR_BG_0;
-               mainButton->bdColor  = COLOR_BD_0;
-               mainButton->txtColor = COLOR_TEXT_0;
-      break;
-    case STATUS_PLAY:
-               mainButton->bgColor0 = COLOR_BG_2;
-               mainButton->bdColor  = COLOR_BD_1;
-               mainButton->txtColor = COLOR_TEXT_1;
-      break;
-    case STATUS_WAIT:
-      blink();
-      break;
-    case STATUS_ENDING:
-      mainButton->bgColor0 = COLOR_BD_0;
-      break;
-  }
-
-  switch (recStatus) {
-    case REC_WAITING:
-      blink();
-      break;
-    case REC_ENDING:
-      mainButton->bgColor0 = COLOR_BD_0;
-      break;
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gChannel::handleKey(int e, int key)
-{
-       int ret;
-       if (e == FL_KEYDOWN && button->value())                              // key already pressed! skip it
-               ret = 1;
-       else
-       if (Fl::event_key() == key && !button->value()) {
-               button->take_focus();                                              // move focus to this button
-               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
-               button->do_callback();                                             // invoke the button's callback
-               ret = 1;
-       }
-       else
-               ret = 0;
-
-       if (Fl::event_key() == key)
-               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
-
-       return ret;
-}
-
-
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L)
-: Fl_Box(x, y, w, h, L), ch(ch) {}
-
-void gStatus::draw()
-{
-  fl_rect(x(), y(), w(), h(), COLOR_BD_0);              // reset border
-  fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);     // reset background
-
-  if (ch != NULL) {
-    if (ch->status    & (STATUS_WAIT | STATUS_ENDING | REC_ENDING | REC_WAITING) ||
-        ch->recStatus & (REC_WAITING | REC_ENDING))
-    {
-      fl_rect(x(), y(), w(), h(), COLOR_BD_1);
-    }
-    else
-    if (ch->status == STATUS_PLAY)
-      fl_rect(x(), y(), w(), h(), COLOR_BD_1);
-    else
-      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);     // status empty
-
-
-    if (G_Mixer.chanInput == ch)
-      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3);     // take in progress
-    else
-    if (recorder::active && recorder::canRec(ch))
-      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4);     // action record
-
-    /* equation for the progress bar:
-     * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */
-
-    int pos = ch->getPosition();
-    if (pos == -1)
-      pos = 0;
-    else
-      pos = (pos * (w()-1)) / (ch->end - ch->begin);
-    fl_rectf(x()+1, y()+1, pos, h()-2, COLOR_BG_2);
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gModeBox::gModeBox(int x, int y, int w, int h, SampleChannel *ch, const char *L)
-  : Fl_Menu_Button(x, y, w, h, L), ch(ch)
-{
-  box(G_BOX);
-  textsize(11);
-  textcolor(COLOR_TEXT_0);
-  color(COLOR_BG_0);
-
-  add("Loop . basic",      0, cb_change_chanmode, (void *)LOOP_BASIC);
-  add("Loop . once",       0, cb_change_chanmode, (void *)LOOP_ONCE);
-  add("Loop . once . bar", 0, cb_change_chanmode, (void *)LOOP_ONCE_BAR);
-  add("Loop . repeat",     0, cb_change_chanmode, (void *)LOOP_REPEAT);
-  add("Oneshot . basic",   0, cb_change_chanmode, (void *)SINGLE_BASIC);
-  add("Oneshot . press",   0, cb_change_chanmode, (void *)SINGLE_PRESS);
-  add("Oneshot . retrig",  0, cb_change_chanmode, (void *)SINGLE_RETRIG);
-  add("Oneshot . endless", 0, cb_change_chanmode, (void *)SINGLE_ENDLESS);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gModeBox::draw() {
-  fl_rect(x(), y(), w(), h(), COLOR_BD_0);    // border
-  switch (ch->mode) {
-    case LOOP_BASIC:
-      fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1);
-      break;
-    case LOOP_ONCE:
-      fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1);
-      break;
-    case LOOP_ONCE_BAR:
-      fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1);
-      break;
-    case LOOP_REPEAT:
-      fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1);
-      break;
-    case SINGLE_BASIC:
-      fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1);
-      break;
-    case SINGLE_PRESS:
-      fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1);
-      break;
-    case SINGLE_RETRIG:
-      fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1);
-      break;
-    case SINGLE_ENDLESS:
-      fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1);
-      break;
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gModeBox::cb_change_chanmode(Fl_Widget *v, void *p) { ((gModeBox*)v)->__cb_change_chanmode((intptr_t)p); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gModeBox::__cb_change_chanmode(int mode)
-{
-  ch->mode = mode;
-
-  /* what to do when the channel is playing and you change the mode?
-   * Nothing, since v0.5.3. Just refresh the action editor window, in
-   * case it's open */
-
-  gu_refreshActionEditor();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gMainButton::gMainButton(int x, int y, int w, int h, const char *l)
-  : gClick(x, y, w, h, l) {}
diff --git a/src/ge_channel.h b/src/ge_channel.h
deleted file mode 100644 (file)
index 113f537..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_CHANNEL_H
-#define GE_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_mixed.h"
-
-
-class gChannel : public Fl_Group
-{
-protected:
-
-       /* define some breakpoints for dynamic resize */
-
-#ifdef WITH_VST
-       static const int BREAK_READ_ACTIONS = 212;
-       static const int BREAK_MODE_BOX     = 188;
-       static const int BREAK_FX           = 164;
-       static const int BREAK_DELTA        = 120;
-#else
-       static const int BREAK_READ_ACTIONS = 188;
-       static const int BREAK_MODE_BOX     = 164;
-       static const int BREAK_FX           = 140;
-       static const int BREAK_DELTA        = 96;
-#endif
-       static const int BREAK_UNIT         = 24;
-
-       /* blink
-        * blink button when channel is in wait/ending status. */
-
-       void blink();
-
-       /* setColorByStatus
-        * update colors depending on channel status. */
-
-       void setColorsByStatus(int playStatus, int recStatus);
-
-       /* handleKey
-        * method wrapped by virtual handle(int e). */
-
-       int handleKey(int e, int key);
-
-public:
-
-       gChannel(int x, int y, int w, int h, int type);
-
-       /* reset
-        * reset channel to initial status. */
-
-       virtual void reset() = 0;
-
-       /* update
-        * update the label of sample button and everything else such as 'R'
-        * button, key box and so on, according to global values. */
-
-       virtual void update() = 0;
-
-       /* refresh
-        * update graphics. */
-
-       virtual void refresh() = 0;
-
-       /* keypress
-        * what to do when the corresponding key is pressed. */
-
-       virtual int keyPress(int event) = 0;
-
-       /* getColumnIndex
-        * return the numeric index of the column in which this channel is
-        * located. */
-
-       int getColumnIndex();
-
-       class gButton *button;
-       class gStatus *status;
-       class gMainButton *mainButton;
-       class gDial   *vol;
-       class gClick    *mute;
-       class gClick    *solo;
-#ifdef WITH_VST
-       class gFxButton *fx;
-#endif
-
-       int type;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gStatus : public Fl_Box
-{
-public:
-       gStatus(int X, int Y, int W, int H, class SampleChannel *ch, const char *L=0);
-       void draw();
-       class SampleChannel *ch;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gModeBox : public Fl_Menu_Button
-{
-private:
-       static void cb_change_chanmode(Fl_Widget *v, void *p);
-       inline void __cb_change_chanmode(int mode);
-
-       class SampleChannel *ch;
-
-public:
-       gModeBox(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0);
-       void draw();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gMainButton
- * base main button for MIDI and Sample Channels. */
-
-class gMainButton : public gClick
-{
-public:
-       gMainButton(int x, int y, int w, int h, const char *l=0);
-       virtual int handle(int e) = 0;
-};
-
-
-#endif
diff --git a/src/ge_column.cpp b/src/ge_column.cpp
deleted file mode 100644 (file)
index 9acabd6..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_column
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "ge_column.h"
-#include "gd_mainWindow.h"
-#include "gd_warnings.h"
-#include "gg_keyboard.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "ge_midiChannel.h"
-#include "mixer.h"
-#include "conf.h"
-#include "log.h"
-#include "patch.h"
-#include "glue.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-
-#ifdef WITH_VST
-       #include "gd_pluginList.h"
-#endif
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch                G_Patch;
-extern gdMainWindow *mainWin;
-
-
-gColumn::gColumn(int X, int Y, int W, int H, int index, gKeyboard *parent)
-       : Fl_Group(X, Y, W, H), parent(parent), index(index)
-{
-  /* gColumn does a bit of a mess: we pass a pointer to its parent (gKeyboard) and
-  the gColumn itself deals with the creation of another widget, outside gColumn
-  and inside gKeyboard, which handles the vertical resize bar (gResizerBar).
-  The resizer cannot stay inside gColumn: it needs a broader view on the other
-  side widgets. The view can be obtained from gKeyboard only (the upper level).
-  Unfortunately, parent() can be NULL: at this point (i.e the constructor)
-  gColumn is still detached from any parent. We use a custom gKeyboard *parent
-  instead. */
-
-       begin();
-       addChannelBtn = new gClick(x(), y(), w(), 20, "Add new channel");
-       end();
-
-  resizer = new gResizerBar(x()+w(), y(), 16, h(), false);
-  resizer->setMinSize(140);
-  parent->add(resizer);
-
-       addChannelBtn->callback(cb_addChannel, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gColumn::~gColumn()
-{
-  /* FIXME - this could actually cause a memory leak. resizer is
-  just removed, not deleted. But we cannot delete it right now. */
-
-  parent->remove(resizer);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gColumn::handle(int e)
-{
-       switch (e) {
-               case FL_DND_ENTER:              // return(1) for these events to 'accept' dnd
-               case FL_DND_DRAG:
-               case FL_DND_RELEASE: {
-                       return 1;
-               }
-               case FL_PASTE: {              // handle actual drop (paste) operation
-                       gVector<std::string> paths;
-                       gSplit(Fl::event_text(), "\n", &paths);
-                       bool fails = false;
-                       int result = 0;
-                       for (unsigned i=0; i<paths.size; i++) {
-                               gLog("[gColumn::handle] loading %s...\n", paths.at(i).c_str());
-                               SampleChannel *c = (SampleChannel*) glue_addChannel(index, CHANNEL_SAMPLE);
-                               result = glue_loadChannel(c, gStripFileUrl(paths.at(i).c_str()).c_str());
-                               if (result != SAMPLE_LOADED_OK) {
-                                       deleteChannel(c->guiChannel);
-                                       fails = true;
-                               }
-                       }
-                       if (fails) {
-                               if (paths.size > 1)
-                                       gdAlert("Some files were not loaded successfully.");
-                               else
-                                       parent->printChannelMessage(result);
-                       }
-                       return 1;
-               }
-       }
-
-       /* we return fl_Group::handle only if none of the cases above are fired. That
-       is because we don't want to propagate a dnd drop to all the sub widgets. */
-
-       return Fl_Group::handle(e);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::resize(int X, int Y, int W, int H)
-{
-  /* resize all children */
-
-  int ch = children();
-  for (int i=0; i<ch; i++) {
-    Fl_Widget *c = child(i);
-    c->resize(X, Y + (i * (c->h() + 4)), W, c->h());
-  }
-
-  /* resize group itself */
-
-  x(X); y(Y); w(W); h(H);
-
-  /* resize resizerBar */
-
-  resizer->size(16, H);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::refreshChannels()
-{
-       for (int i=1; i<children(); i++)
-               ((gChannel*) child(i))->refresh();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::draw()
-{
-       fl_color(fl_rgb_color(27, 27, 27));
-       fl_rectf(x(), y(), w(), h());
-
-  /* call draw and then redraw in order to avoid channel corruption when
-  scrolling horizontally */
-
-  for (int i=0; i<children(); i++) {
-    child(i)->draw();
-    child(i)->redraw();
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChannel(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gChannel *gColumn::addChannel(class Channel *ch)
-{
-       gChannel *gch = NULL;
-
-       if (ch->type == CHANNEL_SAMPLE)
-               gch = (gSampleChannel*) new gSampleChannel(
-                               x(),
-                               y() + children() * 24,
-                               600, // (1) see notes below
-                               20,
-                               (SampleChannel*) ch);
-       else
-               gch = (gMidiChannel*) new gMidiChannel(
-                               x(),
-                               y() + children() * 24,
-                               w(),
-                               20,
-                               (MidiChannel*) ch);
-
-       /* (1) we create a new sample channel with a fake width, instead of w() (i.e.
-       the column width), in case the column is too narrow to display all widgets.
-       This workaround prevents the widgets to disappear if they have an initial
-       negative width. MidiChannel does not need such hack because it already fits
-       nicely in a collapsed column. */
-
-       add(gch);
-  resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop
-  gch->redraw();    // avoid corruption
-       parent->redraw(); // redraw Keyboard
-       return gch;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::deleteChannel(gChannel *gch)
-{
-       gch->hide();
-       remove(gch);
-       delete gch;
-
-       /* reposition all other channels and resize this group */
-       /** TODO
-        * reposition is useless when called by gColumn::clear(). Add a new
-        * parameter to skip the operation */
-
-       for (int i=0; i<children(); i++) {
-               gch = (gChannel*) child(i);
-               gch->position(gch->x(), y()+(i*24));
-       }
-       size(w(), children() * 24 + 66);  // evil space for drag n drop
-       redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::__cb_addChannel()
-{
-       gLog("[gColumn::__cb_addChannel] index = %d\n", index);
-       int type = openTypeMenu();
-       if (type)
-               glue_addChannel(index, type);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gColumn::openTypeMenu()
-{
-       Fl_Menu_Item rclick_menu[] = {
-               {"Sample channel"},
-               {"MIDI channel"},
-               {0}
-       };
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(11);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-       if (!m) return 0;
-
-       if (strcmp(m->label(), "Sample channel") == 0)
-               return CHANNEL_SAMPLE;
-       if (strcmp(m->label(), "MIDI channel") == 0)
-               return CHANNEL_MIDI;
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gColumn::clear(bool full)
-{
-       if (full)
-               Fl_Group::clear();
-       else {
-               while (children() >= 2) {  // skip "add new channel" btn
-                       int i = children()-1;
-                       deleteChannel((gChannel*)child(i));
-               }
-       }
-}
diff --git a/src/ge_column.h b/src/ge_column.h
deleted file mode 100644 (file)
index 84ebc8a..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_column
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_COLUMN_H
-#define GE_COLUMN_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-
-
-class gColumn : public Fl_Group
-{
-private:
-
-       static void cb_addChannel  (Fl_Widget *v, void *p);
-       inline void __cb_addChannel();
-
-       int openTypeMenu();
-
-       class gClick      *addChannelBtn;
-       class gResizerBar *resizer;
-       class gKeyboard   *parent;
-
-       int index;
-
-public:
-
-       gColumn(int x, int y, int w, int h, int index, class gKeyboard *parent);
-       ~gColumn();
-
-       /* addChannel
-        * add a new channel in this column and set the internal pointer
-        * to channel to 'ch'. */
-
-       class gChannel *addChannel(class Channel *ch);
-
-       /* handle */
-
-       int handle(int e);
-
-  /* resize
-   * custom resize behavior. */
-
-  void resize(int x, int y, int w, int h);
-
-       /* deleteChannel
-        * remove the channel 'gch' from this column. */
-
-       void deleteChannel(gChannel *gch);
-
-       /* refreshChannels
-        * update channels' graphical statues. Called on each GUI cycle. */
-
-       void refreshChannels();
-
-       /* clear
-        * remove all channels from the column. If full==true, delete also the
-        * "add new channel" button. This method ovverrides the inherited one
-        * from Fl_Group. */
-
-       void clear(bool full=false);
-
-       void draw();
-
-       inline int  getIndex()      { return index; }
-       inline void setIndex(int i) { index = i; }
-       inline bool isEmpty()       { return children() == 1; }
-};
-
-
-#endif
diff --git a/src/ge_envelopeChannel.cpp b/src/ge_envelopeChannel.cpp
deleted file mode 100644 (file)
index 442f6ba..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_envelopeWidget
- *
- * Parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "ge_envelopeChannel.h"
-#include "gd_actionEditor.h"
-#include "gd_mainWindow.h"
-#include "gg_keyboard.h"
-#include "channel.h"
-#include "recorder.h"
-#include "mixer.h"
-
-
-extern Mixer         G_Mixer;
-extern gdMainWindow *mainWin;
-
-
-gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l)
-       :       gActionWidget(x, y, 200, 80, pParent), l(l), type(type), range(range),
-               selectedPoint(-1), draggedPoint(-1)
-{
-       size(pParent->totalWidth, h());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gEnvelopeChannel::~gEnvelopeChannel() {
-       clearPoints();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int py) {
-       point p;
-       p.frame  = frame;
-       p.iValue = iValue;
-       p.fValue = fValue;
-       p.x = px;
-       p.y = py;
-       points.add(p);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::updateActions() {
-       for (unsigned i=0; i<points.size; i++)
-               points.at(i).x = points.at(i).frame / pParent->zoom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::draw() {
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT));
-
-       int pxOld = x()-3;
-       int pyOld = y()+1;
-       int pxNew = 0;
-       int pyNew = 0;
-
-       fl_color(COLOR_BG_2);
-
-       for (unsigned i=0; i<points.size; i++) {
-
-               pxNew = points.at(i).x+x()-3;
-               pyNew = points.at(i).y+y();
-
-               if (selectedPoint == (int) i) {
-                       fl_color(COLOR_BD_1);
-                       fl_rectf(pxNew, pyNew, 7, 7);
-                       fl_color(COLOR_BG_2);
-               }
-               else
-                       fl_rectf(pxNew, pyNew, 7, 7);
-
-               if (i > 0)
-                       fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3);
-
-               pxOld = pxNew;
-               pyOld = pyNew;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::handle(int e) {
-
-       /* Adding an action: no further checks required, just record it on frame
-        * mx*pParent->zoom. Deleting action is trickier: find the active
-        * point and derive from it the corresponding frame. */
-
-       int ret = 0;
-       int mx  = Fl::event_x()-x();  // mouse x
-       int my  = Fl::event_y()-y();  // mouse y
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       ret = 1;
-                       break;
-               }
-
-               case FL_MOVE: {
-                       selectedPoint = getSelectedPoint();
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH: {
-
-                       /* left click on point: drag
-                        * right click on point: delete
-                        * left click on void: add */
-
-                       if (Fl::event_button1()) {
-
-                               if (selectedPoint != -1) {
-                                       draggedPoint = selectedPoint;
-                               }
-                               else {
-
-                                       /* top & border fix */
-
-                                       if (my > h()-8) my = h()-8;
-                                       if (mx > pParent->coverX-x()) mx = pParent->coverX-x();
-
-                                       if (range == RANGE_FLOAT) {
-
-                                               /* if this is the first point ever, add other two points at the beginning
-                                                * and the end of the range */
-
-                                               if (points.size == 0) {
-                                                       addPoint(0, 0, 1.0f, 0, 1);
-                                                       recorder::rec(pParent->chan->index, type, 0, 0, 1.0f);
-                                                       addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1);
-                                                       recorder::rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f);
-                                               }
-
-                                               /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */
-
-                                               int frame   = mx * pParent->zoom;
-                                               float value = (my - h() + 8) / (float) (1 - h() + 8);
-                                               addPoint(frame, 0, value, mx, my);
-                                               recorder::rec(pParent->chan->index, type, frame, 0, value);
-                                               recorder::sortActions();
-                                               sortPoints();
-                                       }
-                                       else {
-                                               /// TODO
-                                       }
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       redraw();
-                               }
-                       }
-                       else {
-
-                               /* right click on point 0 or point size-1 deletes the entire envelope */
-
-                               if (selectedPoint != -1) {
-                                       if (selectedPoint == 0 || (unsigned) selectedPoint == points.size-1) {
-                                               recorder::clearAction(pParent->chan->index, type);
-                                               points.clear();
-                                       }
-                                       else {
-                                               recorder::deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false);
-                                               recorder::sortActions();
-                                               points.del(selectedPoint);
-                                       }
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       redraw();
-                               }
-                       }
-
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-                       if (draggedPoint != -1) {
-
-                               if (points.at(draggedPoint).x == previousXPoint) {
-                                       //gLog("nothing to do\n");
-                               }
-                               else {
-                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
-
-                                       /* x edge correction */
-
-                                       if (newFrame < 0)
-                                               newFrame = 0;
-                                       else if (newFrame > G_Mixer.totalFrames)
-                                               newFrame = G_Mixer.totalFrames;
-
-                                       /* vertical line check */
-
-                                       int vp = verticalPoint(points.at(draggedPoint));
-                                       if (vp == 1)                     newFrame -= 256;
-                                       else if (vp == -1) newFrame += 256;
-
-                                       /*  delete previous point and record a new one */
-
-                                       recorder::deleteAction(pParent->chan->index,    points.at(draggedPoint).frame, type, false);
-
-                                       if (range == RANGE_FLOAT) {
-                                               float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8);
-                                               recorder::rec(pParent->chan->index, type, newFrame, 0, value);
-                                       }
-                                       else {
-                                               /// TODO
-                                       }
-
-                                       recorder::sortActions();
-                                       points.at(draggedPoint).frame = newFrame;
-                                       draggedPoint  = -1;
-                                       selectedPoint = -1;
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       if (draggedPoint != -1) {
-
-                               /* y constraint */
-
-                               if (my > h()-8)
-                                       points.at(draggedPoint).y = h()-8;
-                               else
-                               if (my < 1)
-                                       points.at(draggedPoint).y = 1;
-                               else
-                                       points.at(draggedPoint).y = my;
-
-                               /* x constraint
-                                * constrain the point between two ends (leftBorder-point, point-point,
-                                * point-rightBorder). First & last points cannot be shifted on x */
-
-                               if (draggedPoint == 0)
-                                       points.at(draggedPoint).x = x()-8;
-                               else
-                               if ((unsigned) draggedPoint == points.size-1)
-                                       points.at(draggedPoint).x = pParent->coverX;
-                               else {
-                                       int prevPoint = points.at(draggedPoint-1).x;
-                                       int nextPoint = points.at(draggedPoint+1).x;
-                                       if (mx <= prevPoint)
-                                               points.at(draggedPoint).x = prevPoint;
-                                       else
-                                       if (mx >= nextPoint)
-                                               points.at(draggedPoint).x = nextPoint;
-                                       //else
-                                       //      points.at(draggedPoint).x = mx;
-                                       else {
-                                               if (pParent->gridTool->isOn())
-                                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mx)-1;
-                                               else
-                                                       points.at(draggedPoint).x = mx;
-                                       }
-                               }
-                               redraw();
-                       }
-
-                       ret = 1;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::verticalPoint(const point &p) {
-       for (unsigned i=0; i<points.size; i++) {
-               if (&p == &points.at(i)) {
-                       if (i == 0 || i == points.size-1)  // first or last point
-                               return 0;
-                       else {
-                               if (points.at(i-1).x == p.x)    // vertical with point[i-1]
-                                       return -1;
-                               else
-                               if (points.at(i+1).x == p.x)    // vertical with point[i+1]
-                                       return 1;
-                       }
-                       break;
-               }
-       }
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::sortPoints() {
-       for (unsigned i=0; i<points.size; i++)
-               for (unsigned j=0; j<points.size; j++)
-                       if (points.at(j).x > points.at(i).x)
-                               points.swap(j, i);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::getSelectedPoint() {
-
-       /* point is a 7x7 dot */
-
-       for (unsigned i=0; i<points.size; i++) {
-               if (Fl::event_x() >= points.at(i).x+x()-4  &&
-                               Fl::event_x() <= points.at(i).x+x()+4  &&
-                               Fl::event_y() >= points.at(i).y+y()    &&
-                               Fl::event_y() <= points.at(i).y+y()+7)
-               return i;
-       }
-       return -1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::fill() {
-       points.clear();
-       for (unsigned i=0; i<recorder::global.size; i++)
-               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
-                       recorder::action *a = recorder::global.at(i).at(j);
-                       if (a->type == type && a->chan == pParent->chan->index) {
-                               if (range == RANGE_FLOAT)
-                                       addPoint(
-                                               a->frame,                      // frame
-                                               0,                             // int value (unused)
-                                               a->fValue,                     // float value
-                                               a->frame / pParent->zoom,       // x
-                                               ((1-h()+8)*a->fValue)+h()-8);  // y = (b-a)x + a (line between two points)
-                               // else: TODO
-                       }
-               }
-
-}
diff --git a/src/ge_envelopeChannel.h b/src/ge_envelopeChannel.h
deleted file mode 100644 (file)
index 7a1aa24..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_envelopeWidget
- *
- * parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef __GE_ENVELOPECHANNEL_H__
-#define __GE_ENVELOPECHANNEL_H__
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "ge_actionWidget.h"
-#include "utils.h"
-
-
-class gEnvelopeChannel : public gActionWidget {
-
-       const char *l;      // internal label
-       int         type;   // type of action
-       int         range;
-
-       /* point
-        * a single dot in the graph. x = relative frame, y = relative value */
-
-       struct point {
-               int   frame;
-               int   iValue;
-               float fValue;
-               int   x;
-               int   y;
-       };
-
-       /* points
-        * array of points, filled by fillPoints() */
-
-       gVector<point> points;
-
-       /* selectedPoint
-        * which point we are selecting? */
-
-       int selectedPoint;
-
-       /* draggedPoint
-        * which point we are dragging? */
-
-       int draggedPoint;
-
-       /* previousXPoint
-        * x coordinate of point at time t-1. Used to check effective shifts */
-
-       int previousXPoint;
-
-       void draw();
-
-       int handle(int e);
-
-       int getSelectedPoint();
-
-       void sortPoints();
-
-       /* verticalPoint
-        * check if two points form a vertical line. In that case the frame value
-        * would be the same and recorder would go crazy, so shift by a small value
-        * of frames to create a minimal fadein/fadeout level. Return 0: no
-        * vertical points; return 1: vertical with the next one, return -1: vertical
-        * with the previous one. */
-
-       int verticalPoint(const point &p);
-
-public:
-       gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l);
-       ~gEnvelopeChannel();
-
-       /* addPoint
-        * add a point made of frame+value to internal points[]. */
-
-       void addPoint(int frame, int iValue=0, float fValue=0.0f, int x=-1, int y=-1);
-
-       void updateActions();
-
-       /* fill
-        * parse recorder's stack and fill the widget with points. It's up to
-        * the caller to call this method as initialization. */
-
-       void fill();
-
-       inline void clearPoints() { points.clear(); }
-};
-
-#endif
diff --git a/src/ge_midiChannel.cpp b/src/ge_midiChannel.cpp
deleted file mode 100644 (file)
index 33cd991..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "ge_midiChannel.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "gd_mainWindow.h"
-#include "gd_keyGrabber.h"
-#include "gd_midiInput.h"
-#include "gd_editor.h"
-#include "gd_actionEditor.h"
-#include "gd_warnings.h"
-#include "gd_browser.h"
-#include "gd_keyGrabber.h"
-#include "gd_midiOutput.h"
-#include "gg_keyboard.h"
-#include "pluginHost.h"
-#include "mixer.h"
-#include "conf.h"
-#include "patch.h"
-#include "graphics.h"
-#include "channel.h"
-#include "wave.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "glue.h"
-#include "gui_utils.h"
-
-#ifdef WITH_VST
-#include "gd_pluginList.h"
-#endif
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch                G_Patch;
-extern gdMainWindow *mainWin;
-
-
-gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch)
-       : gChannel(X, Y, W, H, CHANNEL_MIDI), ch(ch)
-{
-       begin();
-
-#if defined(WITH_VST)
-  int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
-#else
-       int delta = 96; // (4 widgets * 20) + (4 paddings * 4)
-#endif
-
-       button     = new gButton(x(), y(), 20, 20);
-       mainButton = new gMidiMainButton(button->x()+button->w()+4, y(), w() - delta, 20, "-- MIDI --");
-       mute       = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo       = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
-#if defined(WITH_VST)
-       fx         = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol        = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
-#else
-       vol        = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
-#endif
-
-       end();
-
-  resizable(mainButton);
-
-       update();
-
-       button->callback(cb_button, (void*)this);
-       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
-
-#ifdef WITH_VST
-       fx->callback(cb_openFxWindow, (void*)this);
-#endif
-
-       mute->type(FL_TOGGLE_BUTTON);
-       mute->callback(cb_mute, (void*)this);
-
-       solo->type(FL_TOGGLE_BUTTON);
-       solo->callback(cb_solo, (void*)this);
-
-       mainButton->callback(cb_openMenu, (void*)this);
-       vol->callback(cb_changeVol, (void*)this);
-
-       ch->guiChannel = this;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::cb_button      (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_button(); }
-void gMidiChannel::cb_mute        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_mute(); }
-void gMidiChannel::cb_solo        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_solo(); }
-void gMidiChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openMenu(); }
-void gMidiChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_changeVol(); }
-#ifdef WITH_VST
-void gMidiChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openFxWindow(); }
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_mute()
-{
-       glue_setMute(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_solo()
-{
-       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_changeVol()
-{
-       glue_setChanVol(ch, vol->value());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-void gMidiChannel::__cb_openFxWindow()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
-}
-#endif
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_button()
-{
-       if (button->value())
-               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_openMenu()
-{
-       Fl_Menu_Item rclick_menu[] = {
-               {"Edit actions..."},                        // 0
-               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 1
-                       {"All"},                                  // 2
-                       {0},                                      // 3
-               {"Setup keyboard input..."},                // 5
-               {"Setup MIDI input..."},                    // 6
-               {"Setup MIDI output..."},                   // 7
-               {"Delete channel"},                         // 8
-               {0}
-       };
-
-       /* no 'clear actions' if there are no actions */
-
-       if (!ch->hasActions)
-               rclick_menu[1].deactivate();
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(11);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-       if (strcmp(m->label(), "Delete channel") == 0) {
-               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
-                       return;
-               glue_deleteChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
-               gu_openSubWindow(mainWin, new gdKeyGrabber(ch), 0);
-               //new gdKeyGrabber(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "All") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-                       return;
-               recorder::clearChan(ch->index);
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit actions...") == 0) {
-               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
-               //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0);
-               gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0);
-               return;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::refresh()
-{
-       setColorsByStatus(ch->status, ch->recStatus);
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::reset()
-{
-       mainButton->bgColor0 = COLOR_BG_0;
-       mainButton->bdColor  = COLOR_BD_0;
-       mainButton->txtColor = COLOR_TEXT_0;
-       mainButton->label("-- MIDI --");
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::update()
-{
-       if (ch->midiOut) {
-               char tmp[32];
-               sprintf(tmp, "-- MIDI (channel %d) --", ch->midiOutChan+1);
-               mainButton->copy_label(tmp);
-       }
-       else
-               mainButton->label("-- MIDI --");
-
-       vol->value(ch->volume);
-       mute->value(ch->mute);
-       solo->value(ch->solo);
-
-#ifdef WITH_VST
-       fx->full = ch->plugins.size > 0;
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::resize(int X, int Y, int W, int H)
-{
-  gChannel::resize(X, Y, W, H);
-
-       /* this stuff makes sense only with FX button available. Do nothing
-        * otherwise */
-
-#ifdef WITH_VST
-       if (w() < BREAK_FX) {
-               fx->hide();
-
-               mainButton->size(w() - (BREAK_DELTA - BREAK_UNIT), mainButton->h());
-       }
-       else {
-               fx->show();
-               mainButton->size(w() - BREAK_DELTA, mainButton->h());
-       }
-       mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-       solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-
-       gChannel::init_sizes();
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gMidiChannel::keyPress(int e)
-{
-       return handleKey(e, ch->key);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gMidiMainButton::gMidiMainButton(int x, int y, int w, int h, const char *l)
-       : gMainButton(x, y, w, h, l) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gMidiMainButton::handle(int e)
-{
-       // MIDI drag-n-drop does nothing so far.
-       return gClick::handle(e);
-}
diff --git a/src/ge_midiChannel.h b/src/ge_midiChannel.h
deleted file mode 100644 (file)
index af07fb3..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_MIDI_CHANNEL_H
-#define GE_MIDI_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_channel.h"
-#include "ge_mixed.h"
-
-
-class gMidiChannel : public gChannel
-{
-private:
-
-       static void cb_button        (Fl_Widget *v, void *p);
-       static void cb_mute          (Fl_Widget *v, void *p);
-       static void cb_solo          (Fl_Widget *v, void *p);
-       static void cb_openMenu      (Fl_Widget *v, void *p);
-       static void cb_changeVol     (Fl_Widget *v, void *p);
-#ifdef WITH_VST
-       static void cb_openFxWindow  (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_mute        ();
-       inline void __cb_solo        ();
-       inline void __cb_changeVol   ();
-       inline void __cb_button      ();
-       inline void __cb_openMenu    ();
-       inline void __cb_readActions ();
-#ifdef WITH_VST
-       inline void __cb_openFxWindow();
-#endif
-
-public:
-
-       gMidiChannel(int x, int y, int w, int h,  class MidiChannel *ch);
-
-       void reset   ();
-       void update  ();
-       void refresh ();
-       int  keyPress(int event);
-       void resize  (int x, int y, int w, int h);
-
-       class MidiChannel *ch;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gMidiMainButton : public gMainButton
-{
-public:
-       gMidiMainButton(int x, int y, int w, int h, const char *l=0);
-       int handle(int e);
-};
-
-
-#endif
diff --git a/src/ge_midiIoTools.cpp b/src/ge_midiIoTools.cpp
deleted file mode 100644 (file)
index da9b873..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiIoTools
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "ge_midiIoTools.h"
-#include "ge_mixed.h"
-
-
-gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param)
-       : Fl_Group(X, Y, W, 20),
-               callback(cb),
-               param   (param)
-{
-       begin();
-       text   = new gBox(x(), y(), 156, 20, l);
-       value  = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)");
-       button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn");
-       end();
-
-       text->box(G_BOX);
-       text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-
-       value->box(G_BOX);
-       value->callback(cb_value, (void*)this);
-       value->when(FL_WHEN_RELEASE);
-       updateValue();
-
-       button->type(FL_TOGGLE_BUTTON);
-       button->callback(cb_button, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gLearner::updateValue() {
-       char buf[16];
-       if (*param != 0x0)
-               snprintf(buf, 9, "0x%X", *param);
-       else
-               snprintf(buf, 16, "(not set)");
-       value->copy_label(buf);
-       button->value(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); }
-void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gLearner::__cb_value() {
-       if (Fl::event_button() == FL_RIGHT_MOUSE) {
-               *param = 0x0;
-               updateValue();
-       }
-       /// TODO - elif (LEFT_MOUSE) : insert values by hand
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* FIXME - do not malloc on each callback! do it on the constructor! */
-
-void gLearner::__cb_button() {
-       if (button->value() == 1) {
-               cbData *data  = (cbData*) malloc(sizeof(cbData));
-               data->window  = (gdMidiInput*) parent();  // parent = gdMidiGrabberChannel
-               data->learner = this;
-               kernelMidi::startMidiLearn(callback, (void*)data);
-       }
-       else
-               kernelMidi::stopMidiLearn();
-}
diff --git a/src/ge_midiIoTools.h b/src/ge_midiIoTools.h
deleted file mode 100644 (file)
index bd52756..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiIoTools
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_LEARNER_H
-#define GE_LEARNER_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "gd_midiInput.h"
-#include "kernelMidi.h"
-
-
-class gLearner : public Fl_Group
-{
-private:
-
-       /* callback
-        * cb to pass to kernelMidi. Requires two parameters:
-        * uint32_t msg - MIDI message
-        * void   *data - extra data */
-
-       kernelMidi::cb_midiLearn *callback;
-
-       class gBox    *text;
-       class gClick  *value;
-       class gButton *button;
-
-       static void cb_button(Fl_Widget *v, void *p);
-       static void cb_value (Fl_Widget *v, void *p);
-       inline void __cb_button();
-       inline void __cb_value();
-
-public:
-
-       /* param
-        * pointer to ch->midiIn[value] */
-
-       uint32_t *param;
-
-       gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param);
-
-       void updateValue();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* cbData
- * struct we pass to kernelMidi as extra parameter. Local scope made
- * with unnamed namespace. Infos:
- * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */
-
-/* TODO - instead of the unnamed namespace, why don't we make the struct as a
-(static) member of gLearner? */
-
-namespace {
-       struct cbData {
-               gdMidiInput *window;
-               gLearner    *learner;
-       };
-}
-
-
-#endif
diff --git a/src/ge_mixed.cpp b/src/ge_mixed.cpp
deleted file mode 100644 (file)
index 81200c8..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_mixed
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <math.h>
-#include "ge_mixed.h"
-#include "gd_mainWindow.h"
-#include "const.h"
-#include "mixer.h"
-#include "graphics.h"
-#include "recorder.h"
-#include "gui_utils.h"
-#include "channel.h"
-#include "sampleChannel.h"
-
-
-extern Mixer         G_Mixer;
-extern unsigned      G_beats;
-extern bool          G_audio_status;
-extern gdMainWindow *mainWin;
-
-
-void __cb_window_closer(Fl_Widget *v, void *p)
-{
-  delete (Fl_Window*)p;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gButton::gButton(int X, int Y, int W, int H, const char *L, const char **imgOff, const char **imgOn)
-  : gClick(X, Y, W, H, L, imgOff, imgOn) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gClick::gClick(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn)
-: gBaseButton(x, y, w, h, L),
-  imgOff(imgOff),
-  imgOn(imgOn),
-  bgColor0(COLOR_BG_0),
-  bgColor1(COLOR_BG_1),
-  bdColor(COLOR_BD_0),
-  txtColor(COLOR_TEXT_0)  {}
-
-void gClick::draw()
-{
-  if (!active()) txtColor = bdColor;
-  else           txtColor = COLOR_TEXT_0;
-
-  fl_rect(x(), y(), w(), h(), bdColor);             // borders
-  if (value()) {                                    // -- clicked
-    if (imgOn != NULL)
-      fl_draw_pixmap(imgOn, x()+1, y()+1);
-    else
-      fl_rectf(x(), y(), w(), h(), bgColor1);       // covers the border
-  }
-  else {                                            // -- not clicked
-    fl_rectf(x()+1, y()+1, w()-2, h()-2, bgColor0); // bg inside the border
-    if (imgOff != NULL)
-      fl_draw_pixmap(imgOff, x()+1, y()+1);
-  }
-  if (!active())
-    fl_color(FL_INACTIVE_COLOR);
-
-  fl_color(txtColor);
-  fl_font(FL_HELVETICA, 11);
-  fl_draw(label(), x(), y(), w(), h(), FL_ALIGN_CENTER);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gClickRepeat::gClickRepeat(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn)
-: Fl_Repeat_Button(x, y, w, h, L), imgOff(imgOff), imgOn(imgOn) {}
-
-void gClickRepeat::draw()
-{
-  if (value()) {                               // -- clicked
-    fl_rectf(x(), y(), w(), h(), COLOR_BG_1);  // bg
-    if (imgOn != NULL)
-      fl_draw_pixmap(imgOn, x()+1, y()+1);
-  }
-  else {                                       // -- not clicked
-    fl_rectf(x(), y(), w(), h(), COLOR_BG_0);  // bg
-    fl_rect(x(), y(), w(), h(), COLOR_BD_0);   // border
-    if (imgOff != NULL)
-      fl_draw_pixmap(imgOff, x()+1, y()+1);
-  }
-  if (!active())
-    fl_color(FL_INACTIVE_COLOR);
-
-  fl_color(COLOR_TEXT_0);
-  fl_font(FL_HELVETICA, 11);
-  fl_draw(label(), x(), y(), w(), h(), FL_ALIGN_CENTER);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gInput::gInput(int x, int y, int w, int h, const char *L)
-: Fl_Input(x, y, w, h, L)
-{
-  //Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2);
-  box(G_BOX);
-  labelsize(11);
-  labelcolor(COLOR_TEXT_0);
-  color(COLOR_BG_DARK);
-  textcolor(COLOR_TEXT_0);
-  cursor_color(COLOR_TEXT_0);
-  selection_color(COLOR_BD_0);
-  textsize(11);
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gDial::gDial(int x, int y, int w, int h, const char *L)
-: Fl_Dial(x, y, w, h, L)
-{
-  labelsize(11);
-  labelcolor(COLOR_TEXT_0);
-  align(FL_ALIGN_LEFT);
-  type(FL_FILL_DIAL);
-  angles(0, 360);
-  color(COLOR_BG_0);            // background
-  selection_color(COLOR_BG_1);   // selection
-}
-
-void gDial::draw()
-{
-  double angle = (angle2()-angle1())*(value()-minimum())/(maximum()-minimum()) + angle1();
-
-  fl_color(COLOR_BG_0);
-  fl_pie(x(), y(), w(), h(), 270-angle1(), angle > angle1() ? 360+270-angle : 270-360-angle);
-
-  fl_color(COLOR_BD_0);
-  fl_arc(x(), y(), w(), h(), 0, 360);
-  fl_pie(x(), y(), w(), h(), 270-angle, 270-angle1());
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-gBox::gBox(int x, int y, int w, int h, const char *L, Fl_Align al)
-: Fl_Box(x, y, w, h, L)
-{
-  labelsize(11);
-  box(FL_NO_BOX);
-  labelcolor(COLOR_TEXT_0);
-  if (al != 0)
-    align(al | FL_ALIGN_INSIDE);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gCheck::gCheck(int x, int y, int w, int h, const char *L)
-: Fl_Check_Button(x, y, w, h, L) {}
-
-void gCheck::draw()
-{
-  int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0;
-
-  if (value()) {
-    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
-    fl_rectf(x(), y(), 12, 12, (Fl_Color) color);
-  }
-  else {
-    fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR);
-    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
-  }
-
-  fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
-  fl_font(FL_HELVETICA, 11);
-  fl_color(COLOR_TEXT_0);
-  fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gRadio::gRadio(int x, int y, int w, int h, const char *L)
-: Fl_Radio_Button(x, y, w, h, L) {}
-
-void gRadio::draw()
-{
-  int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0;
-
-  if (value()) {
-    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
-    fl_rectf(x(), y(), 12, 12, (Fl_Color) color);
-  }
-  else {
-    fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR);
-    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
-  }
-
-  fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
-  fl_font(FL_HELVETICA, 11);
-  fl_color(COLOR_TEXT_0);
-  fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gProgress::gProgress(int x, int y, int w, int h, const char *L)
-: Fl_Progress(x, y, w, h, L) {
-  color(COLOR_BG_0, COLOR_BD_0);
-  box(G_BOX);
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gSoundMeter::gSoundMeter(int x, int y, int w, int h, const char *L)
-  : Fl_Box(x, y, w, h, L),
-    clip(false),
-    mixerPeak(0.0f),
-    peak(0.0f),
-    peak_old(0.0f),
-    db_level(0.0f),
-    db_level_old(0.0f) {}
-
-void gSoundMeter::draw()
-{
-  fl_rect(x(), y(), w(), h(), COLOR_BD_0);
-
-  /* peak = the highest value inside the frame */
-
-  peak = 0.0f;
-  float tmp_peak = 0.0f;
-
-  tmp_peak = fabs(mixerPeak);
-  if (tmp_peak > peak)
-    peak = tmp_peak;
-
-  clip = peak >= 1.0f ? true : false; // 1.0f is considered clip
-
-
-  /*  dBFS (full scale) calculation, plus decay of -2dB per frame */
-
-  db_level = 20 * log10(peak);
-  if (db_level < db_level_old)
-    if (db_level_old > -DB_MIN_SCALE)
-      db_level = db_level_old - 2.0f;
-
-  db_level_old = db_level;
-
-  /* graphical part */
-
-  float px_level = 0.0f;
-  if (db_level < 0.0f)
-    px_level = ((w()/DB_MIN_SCALE) * db_level) + w();
-  else
-    px_level = w();
-
-  fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);
-  fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !G_audio_status ? COLOR_ALERT : COLOR_BD_0);
-}
-
-/* -------------------------------------------------------------------------- */
-
-gBeatMeter::gBeatMeter(int x, int y, int w, int h, const char *L)
-  : Fl_Box(x, y, w, h, L) {}
-
-void gBeatMeter::draw()
-{
-  int cursorW = w() / MAX_BEATS;
-  int greyX   = G_Mixer.beats * cursorW;
-
-  fl_rect(x(), y(), w(), h(), COLOR_BD_0);                                // border
-  fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR);              // bg
-  fl_rectf(x()+(G_Mixer.actualBeat*cursorW)+3, y()+3, cursorW-5, h()-6, COLOR_BG_2); // cursor
-
-  /* beat cells */
-
-  fl_color(COLOR_BD_0);
-  for (int i=1; i<=G_Mixer.beats; i++)
-    fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2);
-
-  /* bar line */
-
-  fl_color(COLOR_BG_2);
-  int delta = G_Mixer.beats / G_Mixer.bars;
-  for (int i=1; i<G_Mixer.bars; i++)
-    fl_line(x()+cursorW*(i*delta), y()+1, x()+cursorW*(i*delta), y()+h()-2);
-
-  /* unused grey area */
-
-  fl_rectf(x()+greyX+1, y()+1, w()-greyX-1,  h()-2, COLOR_BG_1);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gChoice::gChoice(int x, int y, int w, int h, const char *l, bool ang)
-  : Fl_Choice(x, y, w, h, l), angle(ang)
-{
-  labelsize(11);
-  labelcolor(COLOR_TEXT_0);
-  box(FL_BORDER_BOX);
-  textsize(11);
-  textcolor(COLOR_TEXT_0);
-  color(COLOR_BG_0);
-}
-
-
-void gChoice::draw()
-{
-  fl_rectf(x(), y(), w(), h(), COLOR_BG_0);              // bg
-  fl_rect(x(), y(), w(), h(), (Fl_Color) COLOR_BD_0);    // border
-  if (angle)
-    fl_polygon(x()+w()-8, y()+h()-1, x()+w()-1, y()+h()-8, x()+w()-1, y()+h()-1);
-
-  /* pick up the text() from the selected item (value()) and print it in
-   * the box and avoid overflows */
-
-  fl_color(!active() ? COLOR_BD_0 : COLOR_TEXT_0);
-  if (value() != -1) {
-    if (fl_width(text(value())) < w()-8) {
-      fl_draw(text(value()), x(), y(), w(), h(), FL_ALIGN_CENTER);
-    }
-    else {
-      std::string tmp = text(value());
-      int size        = tmp.size();
-      while (fl_width(tmp.c_str()) >= w()-16) {
-        tmp.resize(size);
-        size--;
-      }
-      tmp += "...";
-      fl_draw(tmp.c_str(), x(), y(), w(), h(), FL_ALIGN_CENTER);
-    }
-
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gDrawBox(int x, int y, int w, int h, Fl_Color c)
-{
-  fl_color(c);
-  fl_rectf(x, y, w, h);
-  fl_color(COLOR_BD_0);
-  fl_rect(x, y, w, h);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gLiquidScroll::gLiquidScroll(int x, int y, int w, int h, const char *l)
-  : Fl_Scroll(x, y, w, h, l)
-{
-  type(Fl_Scroll::VERTICAL);
-  scrollbar.color(COLOR_BG_0);
-  scrollbar.selection_color(COLOR_BG_1);
-  scrollbar.labelcolor(COLOR_BD_1);
-  scrollbar.slider(G_BOX);
-}
-
-
-void gLiquidScroll::resize(int X, int Y, int W, int H)
-{
-  int nc = children()-2;                // skip hscrollbar and vscrollbar
-  for ( int t=0; t<nc; t++) {           // tell children to resize to our new width
-    Fl_Widget *c = child(t);
-    c->resize(c->x(), c->y(), W-24, c->h());    // W-24: leave room for scrollbar
-  }
-  init_sizes();   // tell scroll children changed in size
-  Fl_Scroll::resize(X,Y,W,H);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gSlider::gSlider(int x, int y, int w, int h, const char *l)
-  : Fl_Slider(x, y, w, h, l)
-{
-  type(FL_HOR_FILL_SLIDER);
-
-  labelsize(11);
-  align(FL_ALIGN_LEFT);
-  labelcolor(COLOR_TEXT_0);
-
-  box(G_BOX);
-  color(COLOR_BG_0);
-  selection_color(COLOR_BD_0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gResizerBar::gResizerBar(int X,int Y,int W,int H, bool vertical)
-  : Fl_Box(X,Y,W,H), vertical(vertical)
-{
-  last_y = 0;
-  min_h  = 30;
-  if (vertical) {
-    orig_h = H;
-    labelsize(H);
-  }
-  else {
-    orig_h = W;
-    labelsize(W);
-  }
-  align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
-  labelfont(FL_COURIER);
-  visible_focus(0);
-}
-
-/*
-gResizerBar::~gResizerBar()
-{
-  gLog("------ resizerbar %p destroyed\n", (void*)this);
-}
-*/
-
-void gResizerBar::HandleDrag(int diff)
-{
-  Fl_Scroll *grp = (Fl_Scroll*)parent();
-  int top;
-  int bot;
-  if (vertical) {
-    top = y();
-    bot = y()+h();
-  }
-  else {
-    top = x();
-    bot = x()+w();
-  }
-
-  // First pass: find widget directly above us with common edge
-  //    Possibly clamp 'diff' if widget would get too small..
-
-  for (int t=0; t<grp->children(); t++) {
-    Fl_Widget *wd = grp->child(t);
-    if (vertical) {
-      if ((wd->y()+wd->h()) == top) {                           // found widget directly above?
-        if ((wd->h()+diff) < min_h)
-          diff = wd->h() - min_h;                              // clamp
-        wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);       // change height
-        break;                                                // done with first pass
-      }
-    }
-    else {
-      if ((wd->x()+wd->w()) == top) {                           // found widget directly above?
-        if ((wd->w()+diff) < min_h)
-          diff = wd->w() - min_h;                              // clamp
-        wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());       // change height
-        break;                                                // done with first pass
-      }
-    }
-  }
-
-  // Second pass: find widgets below us, move based on clamped diff
-
-  for (int t=0; t<grp->children(); t++) {
-    Fl_Widget *wd = grp->child(t);
-    if (vertical) {
-      if (wd->y() >= bot)                                     // found widget below us?
-        wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());      // change position
-    }
-    else {
-      if (wd->x() >= bot)
-        wd->resize(wd->x()+diff, wd->y(), wd->w(), wd->h());
-    }
-  }
-
-  // Change our position last
-
-  if (vertical)
-    resize(x(), y()+diff, w(), h());
-  else
-    resize(x()+diff, y(), w(), h());
-
-  grp->init_sizes();
-  grp->redraw();
-}
-
-
-int gResizerBar::handle(int e)
-{
-  int ret = 0;
-  int this_y;
-  if (vertical)
-    this_y = Fl::event_y_root();
-  else
-    this_y = Fl::event_x_root();
-  switch (e) {
-    case FL_FOCUS:
-      ret = 1;
-      break;
-    case FL_ENTER:
-      ret = 1;
-      fl_cursor(vertical ? FL_CURSOR_NS : FL_CURSOR_WE);
-      break;
-    case FL_LEAVE:
-      ret = 1;
-      fl_cursor(FL_CURSOR_DEFAULT);
-      break;
-    case FL_PUSH:
-      ret = 1;
-      last_y = this_y;
-      break;
-    case FL_DRAG:
-      HandleDrag(this_y-last_y);
-      last_y = this_y;
-      ret = 1;
-      break;
-    default: break;
-  }
-  return(Fl_Box::handle(e) | ret);
-}
-
-
-void gResizerBar::resize(int X,int Y,int W,int H)
-{
-  if (vertical)
-    Fl_Box::resize(X,Y,W,orig_h);                                // height of resizer stays constant size
-  else
-    Fl_Box::resize(X,Y,orig_h,H);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gScroll::gScroll(int x, int y, int w, int h, int t)
-  : Fl_Scroll(x, y, w, h)
-{
-  type(t);
-
-  scrollbar.color(COLOR_BG_0);
-  scrollbar.selection_color(COLOR_BG_1);
-  scrollbar.labelcolor(COLOR_BD_1);
-  scrollbar.slider(G_BOX);
-
-  hscrollbar.color(COLOR_BG_0);
-  hscrollbar.selection_color(COLOR_BG_1);
-  hscrollbar.labelcolor(COLOR_BD_1);
-  hscrollbar.slider(G_BOX);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gBaseButton::gBaseButton(int x, int y, int w, int h, const char *l)
-  : Fl_Button(x, y, w, h, l)
-{
-  initLabel = l ? l : "";
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gBaseButton::trimLabel()
-{
-  if (initLabel.empty())
-    return;
-
-  std::string out;
-  if (w() > 20) {
-    out = initLabel;
-    int len = initLabel.size();
-    while (fl_width(out.c_str(), out.size()) > w()) {
-      out = initLabel.substr(0, len) + "...";
-      len--;
-    }
-  }
-  else
-    out = "";
-    copy_label(out.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gBaseButton::label(const char *l)
-{
-  Fl_Button::label(l);
-  initLabel = l;
-  trimLabel();
-}
-
-const char *gBaseButton::label()
-{
-  return Fl_Button::label();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gBaseButton::resize(int X, int Y, int W, int H)
-{
-  trimLabel();
-  Fl_Button::resize(X, Y, W, H);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gFxButton::gFxButton(int x, int y, int w, int h, const char **imgOff, const char **imgOn)
-  : gClick(x, y, w, h, NULL, imgOff, imgOn), full(false) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gFxButton::draw()
-{
-  gClick::draw();
-  if (full)
-    fl_draw_pixmap(imgOn, x()+1, y()+1, COLOR_BD_0);
-}
diff --git a/src/ge_mixed.h b/src/ge_mixed.h
deleted file mode 100644 (file)
index 26942d5..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_mixed
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_MIXED_H
-#define GE_MIXED_H
-
-#include <stdio.h>
-#include <dirent.h>
-#include <stdint.h>  // for intptr_t
-#include <string>
-#include <FL/Fl.H>
-#include <FL/Fl_Menu_Window.H>
-#include <FL/Fl_Button.H>
-#include <FL/Fl_Repeat_Button.H>
-#include <FL/Fl_Check_Button.H>
-#include <FL/Fl_Box.H>
-#include <FL/fl_draw.H>
-#include <FL/Fl_Dial.H>
-#include <FL/Fl_Pixmap.H>
-#include <FL/Fl_Menu_Button.H>
-#include <FL/Fl_Hold_Browser.H>
-#include <FL/Fl_Radio_Button.H>
-#include <FL/Fl_Progress.H>
-#include <FL/Fl_Input.H>
-#include <FL/Fl_Int_Input.H>
-#include <FL/Fl_Choice.H>
-#include <FL/Fl_Scroll.H>
-
-#ifdef _WIN32
-       #include <shlobj.h>  // for SHGetFolderPath
-#endif
-
-
-/* cb_window_closer
- * callback for when closing windows. Deletes the widget (delete). */
-
-void __cb_window_closer(Fl_Widget *v, void *p);
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gBaseButton : public Fl_Button
-{
-private:
-       std::string initLabel;
-
-       void trimLabel();
-
-public:
-  gBaseButton(int x, int y, int w, int h, const char *l=0);
-  void resize(int x, int y, int w, int h);
-       void label(const char *l);
-       const char *label();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gClick
- * a normal button. */
-
-class gClick : public gBaseButton
-{
-public:
-       gClick(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
-       void draw();
-       const char **imgOff;
-       const char **imgOn;
-       Fl_Color bgColor0;   // background not clicked
-       Fl_Color bgColor1;   // background clicked
-       Fl_Color bdColor;    // border
-       Fl_Color txtColor;       // testo
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gClickRepeat : public Fl_Repeat_Button
-{
-public:
-       gClickRepeat(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
-       void draw();
-       const char **imgOff;
-       const char **imgOn;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gButton
- * exactly as gClick but with a unique id inside of it. Used for the buttons in
- * channels and for FXs. */
-
-class gButton : public gClick
-{
-public:
-       gButton(int X,int Y,int W,int H,const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
-       int key;
-       int id;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gInput : public Fl_Input
-{
-public:
-       gInput(int x, int y, int w, int h, const char *L=0);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gDial : public Fl_Dial
-{
-public:
-       gDial(int x, int y, int w, int h, const char *L=0);
-       void draw();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gBox : public Fl_Box
-{
-public:
-       gBox(int x, int y, int w, int h, const char *L=0, Fl_Align al=FL_ALIGN_CENTER);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gCheck : public Fl_Check_Button
-{
-public:
-       gCheck(int x, int y, int w, int h, const char *L=0);
-       void draw();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gRadio : public Fl_Radio_Button
-{
-public:
-       gRadio(int x, int y, int w, int h, const char *L=0);
-       void draw();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gProgress : public Fl_Progress
-{
-public:
-       gProgress(int x, int y, int w, int h, const char *L=0);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gSoundMeter : public Fl_Box
-{
-public:
-       gSoundMeter(int X,int Y,int W,int H,const char *L=0);
-       void draw();
-       bool clip;
-       float mixerPeak;        // peak from mixer
-private:
-       float peak;
-       float peak_old;
-       float db_level;
-       float db_level_old;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gBeatMeter : public Fl_Box
-{
-public:
-       gBeatMeter(int X,int Y,int W,int H,const char *L=0);
-       void draw();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gChoice : public Fl_Choice
-{
-public:
-
-       gChoice(int X,int Y,int W,int H,const char *L=0, bool angle=true);
-       void draw();
-
-       inline void show(const char *c) {value(find_index(c)); }
-
-       bool angle;
-       int  id;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gDrawBox
- * custom boxes in FLTK. */
-
-#define G_BOX FL_FREE_BOXTYPE
-void gDrawBox(int x, int y, int w, int h, Fl_Color c);
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gLiquidScroll
- * custom scroll that tells children to follow scroll's width when
- * resized. Thanks to Greg Ercolano from FLTK dev team.
- * http://seriss.com/people/erco/fltk/ */
-
-class gLiquidScroll : public Fl_Scroll
-{
-public:
-       gLiquidScroll(int x, int y, int w, int h, const char *l=0);
-       void resize(int x, int y, int w, int h);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gScroll
- * custom scroll with nice scrollbars and something else. */
-
-class gScroll : public Fl_Scroll
-{
-public:
-       gScroll(int x, int y, int w, int h, int type=Fl_Scroll::BOTH);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-/* gResizerBar
- * 'resizer bar' between widgets Fl_Scroll. Thanks to Greg Ercolano from
- * FLTK dev team. http://seriss.com/people/erco/fltk/
- *
- * Shows a resize cursor when hovered over.
- * Assumes:
- *     - Parent is an Fl_Scroll
- *     - All children of Fl_Scroll are vertically arranged
- *     - The widget above us has a bottom edge touching our top edge
- *       ie. (w->y()+w->h() == this->y())
- *
- * When this widget is dragged:
- *     - The widget above us (with a common edge) will be /resized/
- *       vertically
- *     - All children below us will be /moved/ vertically */
-
-/* TODO - use more general variable names
- * (last_y -> last_?, min_h -> min_?, ...) */
-
-class gResizerBar : public Fl_Box
-{
-private:
-  bool vertical;
-       int  orig_h;
-       int  last_y;
-       int  min_h;   // min height for widget above us
-
-       void HandleDrag(int diff);
-
-public:
-
-  /* 'vertical' defines the bar movement. Vertical=true: the bar moves
-   * vertically (up and down). */
-
-       gResizerBar(int x, int y, int w, int h, bool vertical=true);
-       //~gResizerBar();
-
-  inline void setMinSize(int val) { min_h = val; }
-  inline int  getMinSize()        { return min_h; }
-
-  int  handle(int e);
-  void resize(int x, int y, int w, int h);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gSlider : public Fl_Slider
-{
-public:
-       gSlider(int x, int y, int w, int h, const char *l=0);
-       int id;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* gFxButton
- * a simple gClick with 'full' parameter (i.e. has plugins). If 'full' is true,
- * draw something somewhere. */
-
-class gFxButton : public gClick
-{
-public:
-       gFxButton(int x, int y, int w, int h, const char **imgOff=NULL, const char **imgOn=NULL);
-       void draw();
-       bool full;
-};
-
-
-#endif
diff --git a/src/ge_muteChannel.cpp b/src/ge_muteChannel.cpp
deleted file mode 100644 (file)
index 01d1391..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_muteChannel
- * a widget that represents mute actions inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "ge_muteChannel.h"
-#include "gd_actionEditor.h"
-#include "ge_actionWidget.h"
-#include "gd_mainWindow.h"
-#include "gg_keyboard.h"
-#include "recorder.h"
-#include "mixer.h"
-#include "glue.h"
-#include "channel.h"
-#include "log.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-
-
-gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent)
- : gActionWidget(x, y, 200, 80, pParent), draggedPoint(-1), selectedPoint(-1)
-{
-       size(pParent->totalWidth, h());
-       extractPoints();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::draw() {
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       fl_draw("mute", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
-
-       /* draw "on" and "off" labels. Must stay in background */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 9);
-       fl_draw("on",  x()+4, y(),        w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-       fl_draw("off", x()+4, y()+h()-14, w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-
-       /* draw on-off points. On = higher rect, off = lower rect. It always
-        * starts with a note_off */
-
-       fl_color(COLOR_BG_2);
-
-       int pxOld = x()+1;
-       int pxNew = 0;
-       int py    = y()+h()-5;
-       int pyDot = py-6;
-
-       for (unsigned i=0; i<points.size; i++) {
-
-               /* next px */
-
-               pxNew = points.at(i).x+x();
-
-               /* draw line from pxOld to pxNew.
-                * i % 2 == 0: first point, mute_on
-                * i % 2 != 0: second point, mute_off */
-
-               fl_line(pxOld, py, pxNew, py);
-               pxOld = pxNew;
-
-               py = i % 2 == 0 ? y()+4 : y()+h()-5;
-
-               /* draw dots (handles) */
-
-               fl_line(pxNew, y()+h()-5, pxNew, y()+4);
-
-               if (selectedPoint == (int) i) {
-                       fl_color(COLOR_BD_1);
-                       fl_rectf(pxNew-3, pyDot, 7, 7);
-                       fl_color(COLOR_BG_2);
-               }
-               else
-                       fl_rectf(pxNew-3, pyDot, 7, 7);
-       }
-
-       /* last section */
-
-       py = y()+h()-5;
-       fl_line(pxNew+3, py, pParent->coverX+x()-1, py);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::extractPoints() {
-
-       points.clear();
-
-       /* actions are already sorted by recorder::sortActions() */
-
-       for (unsigned i=0; i<recorder::frames.size; i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
-                       if (recorder::global.at(i).at(j)->chan == pParent->chan->index) {
-                               if (recorder::global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) {
-                                       point p;
-                                       p.frame = recorder::frames.at(i);
-                                       p.type  = recorder::global.at(i).at(j)->type;
-                                       p.x     = p.frame / pParent->zoom;
-                                       points.add(p);
-                                       //gLog("[gMuteChannel::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame);
-                               }
-                       }
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::updateActions() {
-       for (unsigned i=0; i<points.size; i++)
-               points.at(i).x = points.at(i).frame / pParent->zoom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gMuteChannel::handle(int e) {
-
-       int ret = 0;
-       int mouseX = Fl::event_x()-x();
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       ret = 1;
-                       break;
-               }
-
-               case FL_MOVE: {
-                       selectedPoint = getSelectedPoint();
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH: {
-
-                       /* left click on point: drag
-                        * right click on point: delete
-                        * left click on void: add */
-
-                       if (Fl::event_button1())  {
-
-                               if (selectedPoint != -1) {
-                                       draggedPoint   = selectedPoint;
-                                       previousXPoint = points.at(selectedPoint).x;
-                               }
-                               else {
-
-                                       /* click on the grey area leads to nowhere */
-
-                                       if (mouseX > pParent->coverX) {
-                                               ret = 1;
-                                               break;
-                                       }
-
-                                       /* click in the middle of a long mute_on (between two points): new actions
-                                        * must be added in reverse: first mute_off then mute_on. Let's find the
-                                        * next point from here. */
-
-                                       unsigned nextPoint = points.size;
-                                       for (unsigned i=0; i<points.size; i++) {
-                                               if (mouseX < points.at(i).x) {
-                                                       nextPoint = i;
-                                                       break;
-                                               }
-                                       }
-
-                                       /* next point odd = mute_on [click here] mute_off
-                                        * next point even = mute_off [click here] mute_on */
-
-                                       int frame_a = mouseX * pParent->zoom;
-                                       int frame_b = frame_a+2048;
-
-                                       if (pParent->gridTool->isOn()) {
-                                               frame_a = pParent->gridTool->getSnapFrame(mouseX);
-                                               frame_b = pParent->gridTool->getSnapFrame(mouseX + pParent->gridTool->getCellSize());
-
-                                               /* with snap=on a point can fall onto another */
-
-                                               if (pointCollides(frame_a) || pointCollides(frame_b)) {
-                                                       ret = 1;
-                                                       break;
-                                               }
-                                       }
-
-                                       /* ensure frame parity */
-
-                                       if (frame_a % 2 != 0) frame_a++;
-                                       if (frame_b % 2 != 0) frame_b++;
-
-                                       /* avoid overflow: frame_b must be within the sequencer range. In that
-                                        * case shift the ON-OFF block */
-
-                                       if (frame_b >= G_Mixer.totalFrames) {
-                                               frame_b = G_Mixer.totalFrames;
-                                               frame_a = frame_b-2048;
-                                       }
-
-                                       if (nextPoint % 2 != 0) {
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_a);
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_b);
-                                       }
-                                       else {
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_a);
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_b);
-                                       }
-                                       recorder::sortActions();
-
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       extractPoints();
-                                       redraw();
-                               }
-                       }
-                       else {
-
-                               /* delete points pair */
-
-                               if (selectedPoint != -1) {
-
-                                       unsigned a;
-                                       unsigned b;
-
-                                       if (points.at(selectedPoint).type == ACTION_MUTEOFF) {
-                                               a = selectedPoint-1;
-                                               b = selectedPoint;
-                                       }
-                                       else {
-                                               a = selectedPoint;
-                                               b = selectedPoint+1;
-                                       }
-
-                                       //gLog("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n",
-                                       //              a, b, points.at(a).frame, points.at(b).frame);
-
-                                       recorder::deleteAction(pParent->chan->index, points.at(a).frame,        points.at(a).type, false); // false = don't check vals
-                                       recorder::deleteAction(pParent->chan->index,    points.at(b).frame,     points.at(b).type, false); // false = don't check vals
-                                       recorder::sortActions();
-
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       extractPoints();
-                                       redraw();
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-
-                       if (draggedPoint != -1) {
-
-                               if (points.at(draggedPoint).x == previousXPoint) {
-                                       //gLog("nothing to do\n");
-                               }
-                               else {
-
-                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
-
-                                       recorder::deleteAction(
-                                                       pParent->chan->index,
-                                                       points.at(draggedPoint).frame,
-                                                       points.at(draggedPoint).type,
-                                                       false);  // don't check values
-
-                                       recorder::rec(
-                                                       pParent->chan->index,
-                                                       points.at(draggedPoint).type,
-                                                       newFrame);
-
-                                       recorder::sortActions();
-
-                                       points.at(draggedPoint).frame = newFrame;
-                               }
-                       }
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       if (draggedPoint != -1) {
-
-                               /* constrain the point between two ends (leftBorder-point,
-                                * point-point, point-rightBorder) */
-
-                               int prevPoint;
-                               int nextPoint;
-
-                               if (draggedPoint == 0) {
-                                       prevPoint = 0;
-                                       nextPoint = points.at(draggedPoint+1).x - 1;
-                                       if (pParent->gridTool->isOn())
-                                               nextPoint -= pParent->gridTool->getCellSize();
-                               }
-                               else
-                               if ((unsigned) draggedPoint == points.size-1) {
-                                       prevPoint = points.at(draggedPoint-1).x + 1;
-                                       nextPoint = pParent->coverX-x();
-                                       if (pParent->gridTool->isOn())
-                                               prevPoint += pParent->gridTool->getCellSize();
-                               }
-                               else {
-                                       prevPoint = points.at(draggedPoint-1).x + 1;
-                                       nextPoint = points.at(draggedPoint+1).x - 1;
-                                       if (pParent->gridTool->isOn()) {
-                                               prevPoint += pParent->gridTool->getCellSize();
-                                               nextPoint -= pParent->gridTool->getCellSize();
-                                       }
-                               }
-
-                               if (mouseX <= prevPoint)
-                                       points.at(draggedPoint).x = prevPoint;
-                               else
-                               if (mouseX >= nextPoint)
-                                       points.at(draggedPoint).x = nextPoint;
-                               else
-                               if (pParent->gridTool->isOn())
-                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mouseX)-1;
-                               else
-                                       points.at(draggedPoint).x = mouseX;
-
-                               redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-       }
-
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gMuteChannel::pointCollides(int frame) {
-       for (unsigned i=0; i<points.size; i++)
-               if (frame == points.at(i).frame)
-                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gMuteChannel::getSelectedPoint() {
-
-       /* point is a 7x7 dot */
-
-       for (unsigned i=0; i<points.size; i++) {
-               if (Fl::event_x() >= points.at(i).x+x()-3 &&
-                               Fl::event_x() <= points.at(i).x+x()+3)
-               return i;
-       }
-       return -1;
-}
diff --git a/src/ge_muteChannel.h b/src/ge_muteChannel.h
deleted file mode 100644 (file)
index 5cb0ca1..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_muteChannel
- * a widget representing mute actions inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GE_MUTECHANNEL_H
-#define GE_MUTECHANNEL_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Widget.H>
-#include <FL/fl_draw.H>
-#include "ge_actionWidget.h"
-#include "utils.h"
-
-
-class gMuteChannel : public gActionWidget {
-
-private:
-
-       /* point
-        * a single dot in the graph. */
-
-       struct point {
-               int  frame;
-               char type;
-               int  x;
-       };
-
-       /* points
-        * array of on/off points, in frames */
-
-       gVector<point> points;
-
-       /* draggedPoint
-        * which point we are dragging? */
-
-       int draggedPoint;
-
-       /* selectedPoint
-        * which point we are selecting? */
-
-       int selectedPoint;
-
-       /* previousXPoint
-        * x coordinate of point at time t-1. Used to check effective shifts */
-
-       int previousXPoint;
-
-       /* extractPoints
-        * va a leggere l'array di azioni di Recorder ed estrae tutti i punti
-        * interessanti mute_on o mute_off. Li mette poi nel gVector points. */
-       void extractPoints();
-
-       /* getSelectedPoint
-        * ritorna l'indice di points[] in base al punto selezionato (quello
-        * con il mouse hover). Ritorna -1 se non trova niente. */
-       int getSelectedPoint();
-
-       /* pointCollides
-        * true if a point collides with another. Used while adding new points
-        * with snap active.*/
-
-       bool pointCollides(int frame);
-
-public:
-
-       gMuteChannel(int x, int y, class gdActionEditor *pParent);
-       void draw();
-       int  handle(int e);
-
-       /* updateActions
-        * calculates new points affected by the zoom. Call this one after
-        * each zoom update. */
-
-       void updateActions();
-};
-
-#endif
diff --git a/src/ge_pianoRoll.cpp b/src/ge_pianoRoll.cpp
deleted file mode 100644 (file)
index 51e8b95..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_pianoRoll
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "ge_pianoRoll.h"
-#include "gd_mainWindow.h"
-#include "gd_actionEditor.h"
-#include "channel.h"
-#include "midiChannel.h"
-#include "const.h"
-#include "kernelMidi.h"
-#include "log.h"
-#include "conf.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-extern Conf             G_Conf;
-
-
-gPianoRollContainer::gPianoRollContainer(int x, int y, class gdActionEditor *pParent)
- : Fl_Scroll(x, y, 200, 422), pParent(pParent)
-{
-       size(pParent->totalWidth, G_Conf.pianoRollH);
-       pianoRoll = new gPianoRoll(x, y, pParent->totalWidth, pParent);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gPianoRollContainer::~gPianoRollContainer() {
-       clear();
-       G_Conf.pianoRollH = h();
-       G_Conf.pianoRollY = pianoRoll->y();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRollContainer::updateActions() {
-       pianoRoll->updateActions();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRollContainer::draw() {
-
-       pianoRoll->size(this->w(), pianoRoll->h());  /// <--- not optimal
-
-       /* clear background */
-
-       fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
-
-       /* clip pianoRoll to pianoRollContainer size */
-
-       fl_push_clip(x(), y(), w(), h());
-       draw_child(*pianoRoll);
-       fl_pop_clip();
-
-       fl_color(COLOR_BD_0);
-       fl_line_style(0);
-       fl_rect(x(), y(), pParent->totalWidth, h());
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gPianoRoll::gPianoRoll(int X, int Y, int W, class gdActionEditor *pParent)
- : gActionWidget(X, Y, W, 40, pParent)
-{
-       resizable(NULL);                      // don't resize children (i.e. pianoItem)
-       size(W, (MAX_NOTES+1) * CELL_H);      // 128 MIDI channels * 15 px height
-
-       if (G_Conf.pianoRollY == -1)
-               position(x(), y()-(h()/2));  // center
-       else
-               position(x(), G_Conf.pianoRollY);
-
-       drawSurface1();
-       drawSurface2();
-
-       /* add actions when the window is opened. Position is zoom-based. MIDI
-        * actions come always in pair: start + end. */
-
-       recorder::sortActions();
-
-       recorder::action *a2   = NULL;
-       recorder::action *prev = NULL;
-
-       for (unsigned i=0; i<recorder::frames.size; i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
-
-                       /* don't show actions > than the grey area */
-                       /** FIXME - can we move this to the outer cycle? */
-
-                       if (recorder::frames.at(i) > G_Mixer.totalFrames)
-                               continue;
-
-                       recorder::action *a1 = recorder::global.at(i).at(j);
-
-                       if (a1->chan != pParent->chan->index)
-                               continue;
-
-                       if (a1->type == ACTION_MIDI) {
-
-                               /* if this action is == to previous one: skip it, we have already
-                                * checked it */
-
-                               if (a1 == prev) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was previous\n");
-                                       continue;
-                               }
-
-                               /* extract MIDI infos from a1: if is note off skip it, we are looking
-                                * for note on only */
-
-                               int a1_type = kernelMidi::getB1(a1->iValue);
-                               int a1_note = kernelMidi::getB2(a1->iValue);
-                               int a1_velo = kernelMidi::getB3(a1->iValue);
-
-                               if (a1_type == 0x80) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was note off\n");
-                                       continue;
-                               }
-
-                               /* search for the next action. Must have: same channel, ACTION_MIDI, greater
-                                * than a1->frame and with MIDI properties of note_off (0x80), same note
-                                * of a1, same velocity of a1 */
-
-                               recorder::getNextAction(
-                                               a1->chan,
-                                               ACTION_MIDI,
-                                               a1->frame,
-                                               &a2,
-                                               kernelMidi::getIValue(0x80, a1_note, a1_velo));
-
-                               /* next action note off found: add a new gPianoItem to piano roll */
-
-                               if (a2) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI pair found, frame_a=%d frame_b=%d, note_a=%d, note_b=%d, type_a=%d, type_b=%d\n",
-                                       //      a1->frame, a2->frame, kernelMidi::getNoteValue(a1->iValue), kernelMidi::getNoteValue(a2->iValue),
-                                       //      kernelMidi::getNoteOnOff(a1->iValue), kernelMidi::getNoteOnOff(a2->iValue));
-                                       new gPianoItem(0, 0, x(), y()+3, a1, a2, pParent);
-                                       prev = a2;
-                                       a2 = NULL;
-                               }
-                               else
-                                       gLog("[gPianoRoll] recorder didn't find action!\n");
-
-                       }
-               }
-       }
-
-       end();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::drawSurface1() {
-
-       surface1 = fl_create_offscreen(40, h());
-       fl_begin_offscreen(surface1);
-
-       /* warning: only w() and h() come from this widget, x and y coordinates
-        * are absolute, since we are writing in a memory chunk */
-
-       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
-
-       fl_line_style(FL_DASH, 0, NULL);
-       fl_font(FL_HELVETICA, 11);
-
-       int octave = 9;
-
-       for (int i=1; i<=MAX_NOTES+1; i++) {
-
-               /* print key note label. C C# D D# E F F# G G# A A# B */
-
-               char note[6];
-               int  step = i % 12;
-
-               switch (step) {
-                       case 1:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dG", octave);
-                               break;
-                       case 2:
-                               sprintf(note, "%dF#", octave);
-                               break;
-                       case 3:
-                               sprintf(note, "%dF", octave);
-                               break;
-                       case 4:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dE", octave);
-                               break;
-                       case 5:
-                               sprintf(note, "%dD#", octave);
-                               break;
-                       case 6:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dD", octave);
-                               break;
-                       case 7:
-                               sprintf(note, "%dC#", octave);
-                               break;
-                       case 8:
-                               sprintf(note, "%dC", octave);
-                               break;
-                       case 9:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dB", octave);
-                               break;
-                       case 10:
-                               sprintf(note, "%dA#", octave);
-                               break;
-                       case 11:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dA", octave);
-                               break;
-                       case 0:
-                               sprintf(note, "%dG#", octave);
-                               octave--;
-                               break;
-               }
-
-               fl_color(fl_rgb_color(54, 54, 54));
-               fl_draw(note, 4, ((i-1)*CELL_H)+1, 30, CELL_H, (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
-
-               /* print horizontal line */
-
-               if (i < 128)
-                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
-       }
-
-       fl_line_style(0);
-       fl_end_offscreen();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::drawSurface2() {
-       surface2 = fl_create_offscreen(40, h());
-       fl_begin_offscreen(surface2);
-       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
-       fl_color(fl_rgb_color(54, 54, 54));
-       fl_line_style(FL_DASH, 0, NULL);
-       for (int i=1; i<=MAX_NOTES+1; i++) {
-               int  step = i % 12;
-               switch (step) {
-                       case 1:
-                       case 4:
-                       case 6:
-                       case 9:
-                       case 11:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               break;
-               }
-               if (i < 128) {
-                       fl_color(fl_rgb_color(54, 54, 54));
-                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
-               }
-       }
-       fl_line_style(0);
-       fl_end_offscreen();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::draw() {
-
-       fl_copy_offscreen(x(), y(), 40, h(), surface1, 0, 0);
-
-#if defined(__APPLE__)
-       for (int i=36; i<pParent->totalWidth; i+=36) /// TODO: i < pParent->coverX is faster
-               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 1, 0);
-#else
-       for (int i=40; i<pParent->totalWidth; i+=40) /// TODO: i < pParent->coverX is faster
-               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 0, 0);
-#endif
-
-       baseDraw(false);
-       draw_children();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gPianoRoll::handle(int e) {
-
-       int ret = Fl_Group::handle(e);
-
-       switch (e) {
-               case FL_PUSH:   {
-
-                       /* avoid click on grey area */
-
-                       if (Fl::event_x() >= pParent->coverX) {
-                               ret = 1;
-                               break;
-                       }
-
-
-                       push_y = Fl::event_y() - y();
-
-                       if (Fl::event_button1()) {
-
-                               /* ax is driven by grid, ay by the height in px of each note */
-
-                               int ax = Fl::event_x();
-                               int ay = Fl::event_y();
-
-                               /* vertical snap */
-
-                               int edge = (ay-y()-3) % 15;
-                               if (edge != 0) ay -= edge;
-
-                               /* if no overlap, add new piano item. Also check that it doesn't
-                                * overflow on the grey area, by shifting it to the left if
-                                * necessary. */
-
-                               if (!onItem(ax, ay-y()-3)) {
-                                       int greyover = ax+20 - pParent->coverX-x();
-                                       if (greyover > 0)
-                                               ax -= greyover;
-                                       add(new gPianoItem(ax, ay, ax-x(), ay-y()-3, NULL, NULL, pParent));
-                                       redraw();
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-               case FL_DRAG:   {
-
-                       if (Fl::event_button3()) {
-
-                               gPianoRollContainer *prc = (gPianoRollContainer*) parent();
-                               position(x(), Fl::event_y() - push_y);
-
-                               if (y() > prc->y())
-                                       position(x(), prc->y());
-                               else
-                               if (y() < prc->y()+prc->h()-h())
-                                       position(x(), prc->y()+prc->h()-h());
-
-                               prc->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-               case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::updateActions() {
-
-       /* when zooming, don't delete and re-add actions, just MOVE them. This
-        * function shifts the action by a zoom factor. Those singlepress are
-        * stretched, as well */
-
-       gPianoItem *i;
-       for (int k=0; k<children(); k++) {
-               i = (gPianoItem*) child(k);
-
-               //gLog("found point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
-
-               int newX = x() + (i->getFrame_a() / pParent->zoom);
-               int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom);
-               if (newW < 8)
-                       newW = 8;
-               i->resize(newX, i->y(), newW, i->h());
-               i->redraw();
-
-               //gLog("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gPianoRoll::onItem(int rel_x, int rel_y) {
-
-       if (!pParent->chan->hasActions)
-               return false;
-
-       int note = MAX_NOTES - (rel_y / CELL_H);
-
-       int n = children();
-       for (int i=0; i<n; i++) {   // no scrollbars to skip
-
-               gPianoItem *p = (gPianoItem*) child(i);
-               if (p->getNote() != note)
-                       continue;
-
-               /* when 2 segments overlap?
-                * start = the highest value between the two starting points
-                * end   = the lowest value between the two ending points
-                * if start < end then there's an overlap of end-start pixels. We
-                * also add 1 px to the edges in order to gain some space:
-                * [   ][   ]  ---> no
-                * [   ] [   ] ---> yes! */
-
-               int start = p->x() > rel_x ? p->x() : rel_x-1;
-               int end   = p->x()+p->w() < rel_x + 20 ? p->x()+p->w() : rel_x + 21;
-               if (start < end)
-                       return true;
-       }
-       return false;
-}
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gPianoItem::gPianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, gdActionEditor *pParent)
-       : Fl_Box  (X, Y, 20, gPianoRoll::CELL_H-5),
-         a       (a),
-         b       (b),
-               pParent (pParent),
-               selected(false),
-               event_a (0x00),
-               event_b (0x00),
-               changed (false)
-{
-
-       /* a is a pointer: action exists, needs to be displayed */
-
-       if (a) {
-               note    = kernelMidi::getB2(a->iValue);
-               frame_a = a->frame;
-               frame_b = b->frame;
-               event_a = a->iValue;
-               event_b = b->iValue;
-               int newX = rel_x + (frame_a / pParent->zoom);
-               int newY = rel_y + getY(note);
-               int newW = (frame_b - frame_a) / pParent->zoom;
-               resize(newX, newY, newW, h());
-       }
-
-       /* a is null: action needs to be recorded from scratch */
-
-       else {
-               note    = getNote(rel_y);
-               frame_a = rel_x * pParent->zoom;
-               frame_b = (rel_x + 20) * pParent->zoom;
-               record();
-               size((frame_b - frame_a) / pParent->zoom, h());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gPianoItem::overlap() {
-
-       /* when 2 segments overlap?
-        * start = the highest value between the two starting points
-        * end   = the lowest value between the two ending points
-        * if start < end then there's an overlap of end-start pixels. */
-
-       gPianoRoll *pPiano = (gPianoRoll*) parent();
-
-       for (int i=0; i<pPiano->children(); i++) {
-
-               gPianoItem *pItem = (gPianoItem*) pPiano->child(i);
-
-               /* don't check against itself and with different y positions */
-
-               if (pItem == this || pItem->y() != y())
-                       continue;
-
-               int start = pItem->x() >= x() ? pItem->x() : x();
-               int end   = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w();
-               if (start < end)
-                       return true;
-       }
-
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::draw() {
-       int _w = w() > 4 ? w() : 4;
-       //gLog("[gPianoItem] draw me (%p) at x=%d\n", (void*)this, x());
-       fl_rectf(x(), y(), _w, h(), (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::record() {
-
-       /* avoid frame overflow */
-
-       int overflow = frame_b - G_Mixer.totalFrames;
-       if (overflow > 0) {
-               frame_b -= overflow;
-               frame_a -= overflow;
-       }
-
-       /* note off */
-       /** FIXME - use constants */
-       event_a |= (0x90 << 24);   // note on
-       event_a |= (note << 16);   // note value
-       event_a |= (0x3F <<  8);   // velocity
-       event_a |= (0x00);
-
-       event_b |= (0x80 << 24);   // note off
-       event_b |= (note << 16);   // note value
-       event_b |= (0x3F <<  8);   // velocity
-       event_b |= (0x00);
-
-       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a);
-       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::remove() {
-       recorder::deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0);
-       recorder::deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0);
-
-       /* send a note-off in case we are deleting it in a middle of a key_on
-        * key_off sequence. */
-
-       ((MidiChannel*) pParent->chan)->sendMidi(event_b);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gPianoItem::handle(int e) {
-
-       int ret = 0;
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       selected = true;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       selected = false;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-
-               case FL_MOVE: {
-                       onLeftEdge  = false;
-                       onRightEdge = false;
-
-                       if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
-                               onLeftEdge = true;
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       }
-                       else
-                       if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
-                               onRightEdge = true;
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       }
-                       else
-                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH: {
-
-                       push_x = Fl::event_x() - x();
-                       old_x  = x();
-                       old_w  = w();
-
-                       if (Fl::event_button3()) {
-                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                               remove();
-                               hide();   // for Windows
-                               Fl::delete_widget(this);
-                               ((gPianoRoll*)parent())->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       changed = true;
-
-                       gPianoRoll *pr = (gPianoRoll*) parent();
-                       int coverX     = pParent->coverX + pr->x(); // relative coverX
-                       int nx, ny, nw;
-
-                       if (onLeftEdge) {
-                               nx = Fl::event_x();
-                               ny = y();
-                               nw = x()-Fl::event_x()+w();
-                               if (nx < pr->x()) {
-                                       nx = pr->x();
-                                       nw = w()+x()-pr->x();
-                               }
-                               else
-                               if (nx > x()+w()-8) {
-                                       nx = x()+w()-8;
-                                       nw = 8;
-                               }
-                               resize(nx, ny, nw, h());
-                       }
-                       else
-                       if (onRightEdge) {
-                               nw = Fl::event_x()-x();
-                               if (Fl::event_x() < x()+8)
-                                       nw = 8;
-                               else
-                               if (Fl::event_x() > coverX)
-                                       nw = coverX-x();
-                               size(nw, h());
-                       }
-                       else {
-                               nx = Fl::event_x() - push_x;
-                               if (nx < pr->x()+1)
-                                       nx = pr->x()+1;
-                               else
-                               if (nx+w() > coverX)
-                                       nx = coverX-w();
-
-                               /* snapping */
-
-                               if (pParent->gridTool->isOn())
-                                       nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1;
-
-                               position(nx, y());
-                       }
-
-                       /* update screen */
-
-                       redraw();
-                       ((gPianoRoll*)parent())->redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-
-                       /* delete & record the action, only if it doesn't overlap with
-                        * another one */
-
-                       if (overlap()) {
-                               resize(old_x, y(), old_w, h());
-                               redraw();
-                       }
-                       else
-                       if (changed) {
-                               remove();
-                               note    = getNote(getRelY());
-                               frame_a = getRelX() * pParent->zoom;
-                               frame_b = (getRelX()+w()) * pParent->zoom;
-                               record();
-                               changed = false;
-                       }
-
-                       ((gPianoRoll*)parent())->redraw();
-
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
diff --git a/src/ge_pianoRoll.h b/src/ge_pianoRoll.h
deleted file mode 100644 (file)
index 30c04d2..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_pianoRoll
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GE_PIANOROLL_H
-#define GE_PIANOROLL_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include "ge_actionWidget.h"
-#include "recorder.h"
-
-
-class gPianoRollContainer : public Fl_Scroll {
-
-private:
-       class gdActionEditor *pParent;
-       class gPianoRoll     *pianoRoll;
-
-public:
-       gPianoRollContainer(int x, int y, class gdActionEditor *parent);
-       ~gPianoRollContainer();
-       void draw();
-       void updateActions();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gPianoRoll : public gActionWidget {
-
-private:
-
-       /* onItem
-        * is curson on a gPianoItem? */
-
-       bool onItem(int rel_x, int rel_y);
-
-       /* drawSurface*
-        * generate a complex drawing in memory first and copy it to the
-        * screen at a later point in time. Fl_Offscreen surface holds the
-        * necessary data. */
-
-       /* drawSurface1
-        * draw first tile of note values. */
-
-       void drawSurface1();
-
-       /* drawSurface2
-        * draw the rest of the piano roll. */
-
-       void drawSurface2();
-
-       int  push_y;
-       Fl_Offscreen surface1;  // notes, no repeat
-       Fl_Offscreen surface2;  // lines, x-repeat
-
-
-public:
-       gPianoRoll(int x, int y, int w, class gdActionEditor *pParent);
-
-       void draw();
-       int  handle(int e);
-       void updateActions();
-
-       enum { MAX_NOTES = 127, CELL_H = 15 };
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gPianoItem : public Fl_Box {
-
-private:
-
-       /* getRelX/Y
-        * return x/y point of this item, relative to piano roll (and not to
-        * entire screen) */
-
-       inline int getRelY() { return y() - parent()->y() - 3; };
-       inline int getRelX() { return x() - parent()->x(); };
-
-       /* getNote
-        * from a relative_y return the real MIDI note, range 0-127. 15 is
-        * the hardcoded value for note height in pixels */
-
-       inline int getNote(int rel_y) {
-               return gPianoRoll::MAX_NOTES - (rel_y / gPianoRoll::CELL_H);
-       };
-
-       /* getY
-        * from a note, return the y position on piano roll */
-
-       inline int getY(int note) {
-               return (gPianoRoll::MAX_NOTES * gPianoRoll::CELL_H) - (note * gPianoRoll::CELL_H);
-       };
-
-       /* overlap
-        * check if this item don't overlap with another one. */
-
-       bool overlap();
-
-       recorder::action *a;
-       recorder::action *b;
-       class gdActionEditor *pParent;
-
-       bool selected;
-       int  push_x;
-
-       /* MIDI note, start frame, end frame - Used only if it's a newly added
-        * action */ /** FIXME - is it true? */
-
-       int  note;
-       int  frame_a;
-       int  frame_b;
-
-       /* event - bitmasked MIDI events, generated by record() or by ctor if
-        * not newly added action */
-
-       int event_a;
-       int event_b;
-
-       /* changed - if Item has been moved or resized: re-recording needed */
-
-       bool changed;
-
-       /* onLeft,RightEdge - if cursor is on a widget's edge */
-
-       bool onLeftEdge;
-       bool onRightEdge;
-
-       /* old_x, old_w - store previous width and position while dragging
-        * and moving, in order to restore it if overlap */
-
-       int old_x, old_w;
-
-public:
-
-       /* pianoItem ctor
-        * if action *a == NULL, record a new action */
-
-       gPianoItem(int x, int y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, class gdActionEditor *pParent);
-
-       void draw();
-       int  handle(int e);
-       void record();
-       void remove();
-
-       inline int getFrame_a() { return frame_a; }
-       inline int getFrame_b() { return frame_b; }
-       inline int getNote()    { return note;    }
-
-};
-
-#endif
diff --git a/src/ge_sampleChannel.cpp b/src/ge_sampleChannel.cpp
deleted file mode 100644 (file)
index 7d0f846..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_sampleChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "ge_sampleChannel.h"
-#include "gd_mainWindow.h"
-#include "gd_keyGrabber.h"
-#include "gd_midiInput.h"
-#include "gd_editor.h"
-#include "gd_actionEditor.h"
-#include "gd_warnings.h"
-#include "gd_browser.h"
-#include "gd_midiOutput.h"
-#include "gg_keyboard.h"
-#include "pluginHost.h"
-#include "mixer.h"
-#include "conf.h"
-#include "patch.h"
-#include "graphics.h"
-#include "channel.h"
-#include "wave.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "glue.h"
-#include "gui_utils.h"
-
-#ifdef WITH_VST
-#include "gd_pluginList.h"
-#endif
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch                G_Patch;
-extern gdMainWindow *mainWin;
-
-
-gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel *ch)
-       : gChannel(X, Y, W, H, CHANNEL_SAMPLE), ch(ch)
-{
-       begin();
-
-#if defined(WITH_VST)
-  int delta = 168; // (7 widgets * 20) + (7 paddings * 4)
-#else
-       int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
-#endif
-
-       button       = new gButton(x(), y(), 20, 20);
-       status       = new gStatus(button->x()+button->w()+4, y(), 20, 20, ch);
-       mainButton   = new gSampleMainButton(status->x()+status->w()+4, y(), w() - delta, 20, "-- no sample --");
-       modeBox      = new gModeBox(mainButton->x()+mainButton->w()+4, y(), 20, 20, ch);
-       mute         = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo         = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
-       readActions  = NULL; // no 'R' button
-
-#if defined(WITH_VST)
-       fx           = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol          = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
-#else
-       vol          = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
-#endif
-
-       end();
-
-  resizable(mainButton);
-
-       update();
-
-       button->callback(cb_button, (void*)this);
-       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
-
-#ifdef WITH_VST
-       fx->callback(cb_openFxWindow, (void*)this);
-#endif
-
-       mute->type(FL_TOGGLE_BUTTON);
-       mute->callback(cb_mute, (void*)this);
-
-       solo->type(FL_TOGGLE_BUTTON);
-       solo->callback(cb_solo, (void*)this);
-
-       mainButton->callback(cb_openMenu, (void*)this);
-       vol->callback(cb_changeVol, (void*)this);
-
-       ch->guiChannel = this;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::cb_button      (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_button(); }
-void gSampleChannel::cb_mute        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_mute(); }
-void gSampleChannel::cb_solo        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_solo(); }
-void gSampleChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openMenu(); }
-void gSampleChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_changeVol(); }
-void gSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_readActions(); }
-#ifdef WITH_VST
-void gSampleChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openFxWindow(); }
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_mute()
-{
-       glue_setMute(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_solo()
-{
-       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_changeVol()
-{
-       glue_setChanVol(ch, vol->value());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-void gSampleChannel::__cb_openFxWindow()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
-}
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-
-void gSampleChannel::__cb_button()
-{
-       if (button->value())    // pushed
-               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
-       else                    // released
-               glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_openMenu()
-{
-       /* if you're recording (actions or input) no menu is allowed; you can't
-        * do anything, especially deallocate the channel */
-
-       if (G_Mixer.chanInput == ch || recorder::active)
-               return;
-
-       /* the following is a trash workaround for a FLTK menu. We need a gMenu
-        * widget asap */
-
-       Fl_Menu_Item rclick_menu[] = {
-               {"Load new sample..."},                     // 0
-               {"Export sample to file..."},               // 1
-               {"Setup keyboard input..."},                // 2
-               {"Setup MIDI input..."},                    // 3
-               {"Setup MIDI output..."},                   // 4
-               {"Edit sample..."},                         // 5
-               {"Edit actions..."},                        // 6
-               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 7
-                       {"All"},                                  // 8
-                       {"Mute"},                                 // 9
-                       {"Volume"},                               // 10
-                       {"Start/Stop"},                           // 11
-                       {0},                                      // 12
-               {"Free channel"},                           // 13
-               {"Delete channel"},                         // 14
-               {0}
-       };
-
-       if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) {
-               rclick_menu[1].deactivate();
-               rclick_menu[5].deactivate();
-               rclick_menu[13].deactivate();
-       }
-
-       /* no 'clear actions' if there are no actions */
-
-       if (!ch->hasActions)
-               rclick_menu[6].deactivate();
-
-       /* no 'clear start/stop actions' for those channels in loop mode:
-        * they cannot have start/stop actions. */
-
-       if (ch->mode & LOOP_ANY)
-               rclick_menu[10].deactivate();
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(11);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-       if (strcmp(m->label(), "Load new sample...") == 0) {
-               openBrowser(BROWSER_LOAD_SAMPLE);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
-               new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit sample...") == 0) {
-               gu_openSubWindow(mainWin, new gdEditor(ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor
-               return;
-       }
-
-       if (strcmp(m->label(), "Export sample to file...") == 0) {
-               openBrowser(BROWSER_SAVE_SAMPLE);
-               return;
-       }
-
-       if (strcmp(m->label(), "Delete channel") == 0) {
-               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
-                       return;
-               glue_deleteChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Free channel") == 0) {
-               if (ch->status == STATUS_PLAY) {
-                       if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
-                               return;
-               }
-               else if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
-                       return;
-
-               glue_freeChannel(ch);
-
-               /* delete any related subwindow */
-
-               /** FIXME - use gu_closeAllSubwindows() */
-
-               mainWin->delSubWindow(WID_FILE_BROWSER);
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
-               mainWin->delSubWindow(WID_FX_LIST);
-
-               return;
-       }
-
-       if (strcmp(m->label(), "Mute") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF);
-               if (!ch->hasActions)
-                       delActionButton();
-
-               /* TODO - set mute=false */
-
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Start/Stop") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN);
-               if (!ch->hasActions)
-                       delActionButton();
-               gu_refreshActionEditor();  // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Volume") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_VOLUME);
-               if (!ch->hasActions)
-                       delActionButton();
-               gu_refreshActionEditor();  // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "All") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-                       return;
-               recorder::clearChan(ch->index);
-               delActionButton();
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit actions...") == 0) {
-               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
-               return;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_readActions()
-{
-       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::openBrowser(int type)
-{
-       const char *title = "";
-       switch (type) {
-               case BROWSER_LOAD_SAMPLE:
-                       title = "Browse Sample";
-                       break;
-               case BROWSER_SAVE_SAMPLE:
-                       title = "Save Sample";
-                       break;
-               case -1:
-                       title = "Edit Sample";
-                       break;
-       }
-       gWindow *childWin = new gdBrowser(title, G_Conf.samplePath, ch, type);
-       gu_openSubWindow(mainWin, childWin,     WID_FILE_BROWSER);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::refresh()
-{
-  if (!mainButton->visible()) // mainButton invisible? status too (see below)
-    return;
-
-       setColorsByStatus(ch->status, ch->recStatus);
-
-       if (ch->wave != NULL) {
-
-               if (G_Mixer.chanInput == ch)
-                       mainButton->bgColor0 = COLOR_BG_3;
-
-               if (recorder::active) {
-                       if (recorder::canRec(ch)) {
-                               mainButton->bgColor0 = COLOR_BG_4;
-                               mainButton->txtColor = COLOR_TEXT_0;
-                       }
-               }
-               status->redraw(); // status invisible? sampleButton too (see below)
-       }
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::reset()
-{
-       mainButton->bgColor0 = COLOR_BG_0;
-       mainButton->bdColor  = COLOR_BD_0;
-       mainButton->txtColor = COLOR_TEXT_0;
-       mainButton->label("-- no sample --");
-       delActionButton(true); // force==true, don't check, just remove it
-       mainButton->redraw();
-       status->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::update()
-{
-       /* update sample button's label */
-
-       switch (ch->status) {
-               case STATUS_EMPTY:
-                       mainButton->label("-- no sample --");
-                       break;
-               case STATUS_MISSING:
-               case STATUS_WRONG:
-                       mainButton->label("* file not found! *");
-                       break;
-               default:
-                       mainButton->label(ch->wave->name.c_str());
-                       break;
-       }
-
-       /* update channels. If you load a patch with recorded actions, the 'R'
-        * button must be shown. Moreover if the actions are active, the 'R'
-        * button must be activated accordingly. */
-
-       if (ch->hasActions)
-               addActionButton();
-       else
-               delActionButton();
-
-       /* update key box */
-
-       char k[4];
-       sprintf(k, "%c", ch->key);
-       button->copy_label(k);
-       button->redraw();
-
-       /* updates modebox */
-
-       modeBox->value(ch->mode);
-       modeBox->redraw();
-
-       /* update volumes+mute+solo */
-
-       vol->value(ch->volume);
-       mute->value(ch->mute);
-       solo->value(ch->solo);
-
-#ifdef WITH_VST
-       fx->full = ch->plugins.size > 0;
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gSampleChannel::keyPress(int e)
-{
-       return handleKey(e, ch->key);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::addActionButton()
-{
-       /* quit if 'R' exists yet. */
-
-       if (readActions != NULL)
-               return;
-
-       mainButton->size(mainButton->w()-24, mainButton->h());
-
-       redraw();
-
-       readActions = new gClick(mainButton->x() + mainButton->w() + 4,
-                           mainButton->y(), 20, 20, "", readActionOff_xpm,
-                           readActionOn_xpm);
-       readActions->type(FL_TOGGLE_BUTTON);
-       readActions->value(ch->readActions);
-       readActions->callback(cb_readActions, (void*)this);
-       add(readActions);
-
-       /* hard redraw: there's no other way to avoid glitches when moving
-        * the 'R' button */
-
-       mainWin->keyboard->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::delActionButton(bool force)
-{
-       if (readActions == NULL)
-               return;
-
-       /* TODO - readActions check is useless here */
-
-       if (!force && (readActions == NULL || ch->hasActions))
-               return;
-
-       remove(readActions);            // delete from Keyboard group (FLTK)
-       delete readActions;     // delete (C++)
-       readActions = NULL;
-
-       mainButton->size(mainButton->w()+24, mainButton->h());
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::resize(int X, int Y, int W, int H)
-{
-  gChannel::resize(X, Y, W, H);
-
-       if (w() < BREAK_FX) {
-#ifdef WITH_VST
-               fx->hide();
-#endif
-               mainButton->size(w() - BREAK_DELTA, mainButton->h());
-               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-       }
-       else
-       if (w() < BREAK_MODE_BOX) {
-#ifdef WITH_VST
-               fx->show();
-#endif
-               mainButton->size(w() - (BREAK_DELTA + BREAK_UNIT), mainButton->h());
-               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-    modeBox->hide();
-       }
-       else
-       if (w() < BREAK_READ_ACTIONS) {
-    modeBox->show();
-    mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h());
-    modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               if (readActions) {
-      readActions->hide();
-               }
-       }
-       else {
-               if (readActions) {
-      mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 3)), mainButton->h());
-      readActions->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-      readActions->show();
-               }
-       }
-
-       gChannel::init_sizes();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gSampleMainButton::gSampleMainButton(int x, int y, int w, int h, const char *l)
-       : gMainButton(x, y, w, h, l) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gSampleMainButton::handle(int e)
-{
-       int ret = gClick::handle(e);
-       switch (e) {
-               case FL_DND_ENTER:
-               case FL_DND_DRAG:
-               case FL_DND_RELEASE: {
-                       ret = 1;
-                       break;
-               }
-               case FL_PASTE: {
-      gSampleChannel *gch = (gSampleChannel*) parent();   // parent is gSampleChannel
-      SampleChannel  *ch  = gch->ch;
-      int result = glue_loadChannel(ch, gTrim(gStripFileUrl(Fl::event_text())).c_str());
-                       if (result != SAMPLE_LOADED_OK)
-                               mainWin->keyboard->printChannelMessage(result);
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
diff --git a/src/ge_sampleChannel.h b/src/ge_sampleChannel.h
deleted file mode 100644 (file)
index 09238d7..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_sampleChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_SAMPLE_CHANNEL_H
-#define GE_SAMPLE_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_channel.h"
-#include "ge_mixed.h"
-
-
-class gSampleChannel : public gChannel
-{
-private:
-
-       static void cb_button        (Fl_Widget *v, void *p);
-       static void cb_mute          (Fl_Widget *v, void *p);
-       static void cb_solo          (Fl_Widget *v, void *p);
-       static void cb_openMenu      (Fl_Widget *v, void *p);
-       static void cb_changeVol     (Fl_Widget *v, void *p);
-       static void cb_readActions   (Fl_Widget *v, void *p);
-#ifdef WITH_VST
-       static void cb_openFxWindow  (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_mute        ();
-       inline void __cb_solo        ();
-       inline void __cb_changeVol   ();
-       inline void __cb_button      ();
-       inline void __cb_openMenu    ();
-       inline void __cb_readActions ();
-#ifdef WITH_VST
-       inline void __cb_openFxWindow();
-#endif
-
-       void openBrowser(int type);
-
-public:
-
-       gSampleChannel(int x, int y, int w, int h, class SampleChannel *ch);
-
-       void reset   ();
-       void update  ();
-       void refresh ();
-       int  keyPress(int event);
-       void resize  (int x, int y, int w, int h);
-
-       /* add/delActionButton
-        * add or remove 'R' button when actions are available. 'Status' is
-        * the initial status of the button: on or off.
-        * If force==true remove the button with no further checks. */
-
-       void addActionButton();
-       void delActionButton(bool force=false);
-
-       class gModeBox *modeBox;
-       class gClick     *readActions;
-
-       class SampleChannel *ch;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gSampleMainButton : public gMainButton
-{
-public:
-       gSampleMainButton(int x, int y, int w, int h, const char *l=0);
-       int handle(int e);
-};
-
-
-#endif
diff --git a/src/ge_waveform.cpp b/src/ge_waveform.cpp
deleted file mode 100644 (file)
index 5dcbdad..0000000
+++ /dev/null
@@ -1,838 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_waveform
- * an element which represents a waveform.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/Fl_Menu_Item.H>
-#include <FL/Fl_Menu_Button.H>
-#include <samplerate.h>
-#include "ge_waveform.h"
-#include "gd_editor.h"
-#include "wave.h"
-#include "conf.h"
-#include "glue.h"
-#include "mixer.h"
-#include "waveFx.h"
-#include "ge_mixed.h"
-#include "gg_waveTools.h"
-#include "channel.h"
-#include "sampleChannel.h"
-
-
-extern Mixer G_Mixer;
-extern Conf  G_Conf;
-
-
-gWaveform::gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l)
-: Fl_Widget(x, y, w, h, l),
-  chan(ch),
-  menuOpen(false),
-  chanStart(0),
-  chanStartLit(false),
-  chanEnd(0),
-  chanEndLit(false),
-  ratio(0.0f),
-  selectionA(0),
-  selectionB(0),
-  selectionA_abs(0),
-  selectionB_abs(0)
-{
-  data.sup  = NULL;
-  data.inf  = NULL;
-  data.size = 0;
-
-  grid.snap  = G_Conf.sampleEditorGridOn;
-  grid.level = G_Conf.sampleEditorGridVal;
-  
-  stretchToWindow();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gWaveform::~gWaveform() 
-{
-  freeData();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::freeData() 
-{
-  if (data.sup != NULL) {
-    free(data.sup);
-    free(data.inf);
-    data.sup  = NULL;
-    data.inf  = NULL;
-    data.size = 0;
-  }
-  grid.points.clear();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWaveform::alloc(int datasize)
-{
-  ratio = chan->wave->size / (float) datasize;
-
-  if (ratio < 2)
-    return 0;
-
-  freeData();
-
-  data.size = datasize;
-  data.sup  = (int*) malloc(data.size * sizeof(int));
-  data.inf  = (int*) malloc(data.size * sizeof(int));
-
-  int offset = h() / 2;
-  int zero   = y() + offset; // center, zero amplitude (-inf dB)
-
-  /* grid frequency: store a grid point every 'gridFreq' pixel. Must be
-   * even, as always */
-
-  int gridFreq = 0;
-  if (grid.level != 0) {
-    gridFreq = chan->wave->size / grid.level; 
-    if (gridFreq % 2 != 0)
-      gridFreq--;
-  }
-
-  for (int i=0; i<data.size; i++) {
-
-    int pp;  // point prev
-    int pn;  // point next
-
-    /* resampling the waveform, hardcore way. Many thanks to
-     * http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html
-     * Note: we use
-     *   p = j * (m-1 / n)
-     * instead of
-     *   p = j * (m-1 / n-1)
-     * in order to obtain 'datasize' cells to parse (and not datasize-1) */
-
-    pp = i * ((chan->wave->size - 1) / (float) datasize);
-    pn = (i+1) * ((chan->wave->size - 1) / (float) datasize);
-
-    if (pp % 2 != 0) pp -= 1;
-    if (pn % 2 != 0) pn -= 1;
-
-    float peaksup = 0.0f;
-    float peakinf = 0.0f;
-
-    /* scan the original data in chunks */
-
-    int k = pp;
-    while (k < pn) {
-
-      if (chan->wave->data[k] > peaksup)
-        peaksup = chan->wave->data[k];    // FIXME - Left data only
-      else
-      if (chan->wave->data[k] <= peakinf)
-        peakinf = chan->wave->data[k];    // FIXME - Left data only
-
-      /* print grid */
-
-      if (gridFreq != 0)
-        if (k % gridFreq == 0 && k != 0)
-          grid.points.add(i);
-      
-      k += 2;
-    }
-
-    data.sup[i] = zero - (peaksup * chan->boost * offset);
-    data.inf[i] = zero - (peakinf * chan->boost * offset);
-
-    // avoid window overflow
-
-    if (data.sup[i] < y())       data.sup[i] = y();
-    if (data.inf[i] > y()+h()-1) data.inf[i] = y()+h()-1;
-  }
-
-  recalcPoints();
-  return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::recalcPoints() 
-{
-  selectionA = relativePoint(selectionA_abs);
-  selectionB = relativePoint(selectionB_abs);
-  chanStart  = relativePoint(chan->begin / 2);
-
-  /* fix the rounding error when chanEnd is set on the very end of the
-   * sample */
-
-  if (chan->end == chan->wave->size)
-    chanEnd = data.size - 2; // 2 px border
-  else
-    chanEnd = relativePoint(chan->end / 2);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::draw() 
-{
-  /* blank canvas */
-
-  fl_rectf(x(), y(), w(), h(), COLOR_BG_0);
-
-  /* draw selection (if any) */
-
-  if (selectionA != selectionB) {
-
-    int a_x = selectionA + x() - BORDER; // - start;
-    int b_x = selectionB + x() - BORDER; //  - start;
-
-    if (a_x < 0)
-      a_x = 0;
-    if (b_x >= w()-1)
-      b_x = w()-1;
-
-    if (selectionA < selectionB)
-      fl_rectf(a_x+BORDER, y(), b_x-a_x, h(), COLOR_BD_0);
-    else
-      fl_rectf(b_x+BORDER, y(), a_x-b_x, h(), COLOR_BD_0);
-  }
-
-  /* draw waveform from x1 (offset driven by the scrollbar) to x2
-   * (width of parent window). We don't draw the entire waveform,
-   * only the visibile part. */
-
-  int offset = h() / 2;
-  int zero   = y() + offset; // sample zero (-inf dB)
-
-  int wx1 = abs(x() - ((gWaveTools*)parent())->x());
-  int wx2 = wx1 + ((gWaveTools*)parent())->w();
-  if (x()+w() < ((gWaveTools*)parent())->w())
-    wx2 = x() + w() - BORDER;
-
-  fl_color(0, 0, 0);
-  for (int i=wx1; i<wx2; i++) {
-    fl_line(i+x(), zero, i+x(), data.sup[i]);
-    fl_line(i+x(), zero, i+x(), data.inf[i]);
-    
-    /* print grid */
-
-    for (unsigned k=0; k<grid.points.size; k++) {
-      if (grid.points.at(k) == i) {
-        //gLog("draw grid line at %d\n", i);
-        fl_color(fl_rgb_color(54, 54, 54));
-        fl_line_style(FL_DASH, 0, NULL);
-        fl_line(i+x(), y(), i+x(), y()+h());
-        fl_color(0, 0, 0);
-        fl_line_style(FL_SOLID, 0, NULL);
-        break;
-      }
-    }
-  }
-
-  /* border box */
-
-  fl_rect(x(), y(), w(), h(), COLOR_BD_0);
-
-  /* print chanStart */
-
-  int lineX = x()+chanStart+1;
-
-  if (chanStartLit) fl_color(COLOR_BD_1);
-  else              fl_color(COLOR_BD_0);
-
-  /* vertical line */
-
-  fl_line(lineX, y()+1, lineX, y()+h()-2);
-
-  /* print flag and avoid overflow */
-
-  if (lineX+FLAG_WIDTH > w()+x()-2)
-    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
-  else  {
-    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
-    fl_color(255, 255, 255);
-    fl_draw("s", lineX+4, y()+h()-3);
-  }
-
-  /* print chanEnd */
-
-  lineX = x()+chanEnd;
-  if (chanEndLit) fl_color(COLOR_BD_1);
-  else            fl_color(COLOR_BD_0);
-
-  fl_line(lineX, y()+1, lineX, y()+h()-2);
-
-  if (lineX-FLAG_WIDTH < x())
-    fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
-  else {
-    fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
-    fl_color(255, 255, 255);
-    fl_draw("e", lineX-10, y()+10);
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWaveform::handle(int e) 
-{
-  int ret = 0;
-
-  switch (e) {
-
-    case FL_PUSH: {
-
-      mouseX = Fl::event_x();
-      pushed = true;
-
-      if (!mouseOnEnd() && !mouseOnStart()) {
-
-        /* right button? show the menu. Don't set selectionA,B,etc */
-
-        if (Fl::event_button3()) {
-          openEditMenu();
-        }
-        else
-        if (mouseOnSelectionA() || mouseOnSelectionB()) {
-          resized = true;
-        }
-        else {
-          dragged = true;
-          selectionA = Fl::event_x() - x();
-
-          if (selectionA >= data.size) selectionA = data.size;
-
-          selectionB = selectionA;
-          selectionA_abs = absolutePoint(selectionA);
-          selectionB_abs = selectionA_abs;
-        }
-      }
-
-      ret = 1;
-      break;
-    }
-
-    case FL_RELEASE: {
-
-      /* don't recompute points if something is selected */
-
-      if (selectionA != selectionB) {
-        pushed  = false;
-        dragged = false;
-        ret = 1;
-        break;
-      }
-
-      int realChanStart = chan->begin;
-      int realChanEnd   = chan->end;
-
-      if (chanStartLit)
-        realChanStart = absolutePoint(chanStart)*2;
-      else
-      if (chanEndLit)
-        realChanEnd = absolutePoint(chanEnd)*2;
-
-      glue_setBeginEndChannel((gdEditor *) window(), chan, realChanStart, realChanEnd, false);
-
-      pushed  = false;
-      dragged = false;
-
-      redraw();
-      ret = 1;
-      break;
-    }
-
-    case FL_ENTER: {  // enables FL_DRAG
-      ret = 1;
-      break;
-    }
-
-    case FL_LEAVE: {
-      if (chanStartLit || chanEndLit) {
-        chanStartLit = false;
-        chanEndLit   = false;
-        redraw();
-      }
-      ret = 1;
-      break;
-    }
-
-    case FL_MOVE: {
-      mouseX = Fl::event_x();
-      mouseY = Fl::event_y();
-
-      if (mouseOnStart()) {
-        chanStartLit = true;
-        redraw();
-      }
-      else
-      if (chanStartLit) {
-        chanStartLit = false;
-        redraw();
-      }
-
-      if (mouseOnEnd()) {
-        chanEndLit = true;
-        redraw();
-      }
-      else
-      if (chanEndLit) {
-        chanEndLit = false;
-        redraw();
-      }
-
-      if (mouseOnSelectionA())
-        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-      else
-      if (mouseOnSelectionB())
-        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-      else
-        fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-
-      ret = 1;
-      break;
-    }
-
-    case FL_DRAG: {
-
-      /* here the mouse is on the chanStart tool */
-
-      if (chanStartLit && pushed) {
-
-        chanStart = Fl::event_x() - x();
-      
-        if (grid.snap) 
-          chanStart = applySnap(chanStart);
-
-        if (chanStart < 0)
-          chanStart = 0;
-        else
-        if (chanStart >= chanEnd)
-          chanStart = chanEnd-2;
-        
-        redraw();
-      }
-      else
-      if (chanEndLit && pushed) {
-
-        chanEnd = Fl::event_x() - x();
-
-        if (grid.snap) 
-          chanEnd = applySnap(chanEnd);
-
-        if (chanEnd >= data.size - 2)
-          chanEnd = data.size - 2;
-        else
-        if (chanEnd <= chanStart)
-          chanEnd = chanStart + 2;
-
-        redraw();
-      }
-
-      /* here the mouse is on the waveform, i.e. a selection */
-
-      else
-      if (dragged) {
-
-        selectionB = Fl::event_x() - x();
-
-        if (selectionB >= data.size)
-          selectionB = data.size;
-
-        if (selectionB <= 0)
-          selectionB = 0;
-       
-        if (grid.snap)
-          selectionB = applySnap(selectionB);
-
-        selectionB_abs = absolutePoint(selectionB);
-        redraw();
-      }
-
-      /* here the mouse is on a selection boundary i.e. resize */
-      
-      else
-      if (resized) {
-        int pos = Fl::event_x() - x();
-        if (mouseOnSelectionA()) {
-          selectionA     = grid.snap ? applySnap(pos) : pos;
-          selectionA_abs = absolutePoint(selectionA);
-        }
-        else
-        if (mouseOnSelectionB()) {
-          selectionB     = grid.snap ? applySnap(pos) : pos;
-          selectionB_abs = absolutePoint(selectionB);
-        }
-        redraw();
-      }
-      mouseX = Fl::event_x();
-      ret = 1;
-      break;
-    }
-  }
-  return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-/* pixel snap disances (10px) must be equal to those defined in 
- * gWaveform::mouseOnSelectionA() and gWaverfrom::mouseOnSelectionB() */
-/* TODO - use constant for 10px */
-
-int gWaveform::applySnap(int pos)
-{
-  for (unsigned i=0; i<grid.points.size; i++) {
-    if (pos >= grid.points.at(i) - 10 &&
-        pos <= grid.points.at(i) + 10)
-    {
-      return grid.points.at(i);
-    }
-  }
-  return pos;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gWaveform::mouseOnStart() 
-{
-  return mouseX-10 >  chanStart + x() - BORDER              &&
-         mouseX-10 <= chanStart + x() - BORDER + FLAG_WIDTH &&
-         mouseY    >  h() + y() - FLAG_HEIGHT;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gWaveform::mouseOnEnd() 
-{
-  return mouseX-10 >= chanEnd + x() - BORDER - FLAG_WIDTH &&
-         mouseX-10 <= chanEnd + x() - BORDER              &&
-         mouseY    <= y() + FLAG_HEIGHT + 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-/* pixel boundaries (10px) must be equal to the snap factor distance
- * defined in gWaveform::applySnap() */
-
-bool gWaveform::mouseOnSelectionA() 
-{
-  if (selectionA == selectionB)
-    return false;
-  return mouseX >= selectionA-10+x() && mouseX <= selectionA+10+x();
-}
-
-
-bool gWaveform::mouseOnSelectionB() 
-{
-  if (selectionA == selectionB)
-    return false;
-  return mouseX >= selectionB-10+x() && mouseX <= selectionB+10+x();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWaveform::absolutePoint(int p) 
-{
-  if (p <= 0)
-    return 0;
-
-  if (p > data.size)
-    return chan->wave->size / 2;
-
-  return (p * ratio) / 2;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWaveform::relativePoint(int p) 
-{
-  return (ceilf(p / ratio)) * 2;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::openEditMenu() 
-{
-  if (selectionA == selectionB)
-    return;
-
-  menuOpen = true;
-
-  Fl_Menu_Item menu[] = {
-    {"Cut"},
-    {"Trim"},
-    {"Silence"},
-    {"Fade in"},
-    {"Fade out"},
-    {"Smooth edges"},
-    {"Set start/end here"},
-    {0}
-  };
-
-  if (chan->status == STATUS_PLAY) {
-    menu[0].deactivate();
-    menu[1].deactivate();
-  }
-
-  Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-  b->box(G_BOX);
-  b->textsize(11);
-  b->textcolor(COLOR_TEXT_0);
-  b->color(COLOR_BG_0);
-
-  const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-  if (!m) {
-    menuOpen = false;
-    return;
-  }
-
-  /* straightSel() to ensure that point A is always lower than B */
-
-  straightSel();
-
-  if (strcmp(m->label(), "Silence") == 0) {
-    wfx_silence(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
-
-    selectionA = 0;
-    selectionB = 0;
-
-    stretchToWindow();
-    redraw();
-    menuOpen = false;
-    return;
-  }
-
-  if (strcmp(m->label(), "Set start/end here") == 0) {
-
-    glue_setBeginEndChannel(
-        (gdEditor *) window(), // parent
-        chan,
-        absolutePoint(selectionA) * 2,  // stereo!
-        absolutePoint(selectionB) * 2,  // stereo!
-        false, // no recalc (we do it here)
-        false  // don't check
-        );
-
-    selectionA     = 0;
-    selectionB     = 0;
-    selectionA_abs = 0;
-    selectionB_abs = 0;
-
-    recalcPoints();
-    redraw();
-    menuOpen = false;
-    return;
-  }
-
-  if (strcmp(m->label(), "Cut") == 0) {
-    wfx_cut(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
-
-    /* for convenience reset start/end points */
-
-    glue_setBeginEndChannel(
-      (gdEditor *) window(),
-      chan,
-      0,
-      chan->wave->size,
-      false);
-
-    selectionA     = 0;
-    selectionB     = 0;
-    selectionA_abs = 0;
-    selectionB_abs = 0;
-
-    setZoom(0);
-
-    menuOpen = false;
-    return;
-  }
-
-  if (strcmp(m->label(), "Trim") == 0) {
-    wfx_trim(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
-
-    glue_setBeginEndChannel(
-      (gdEditor *) window(),
-      chan,
-      0,
-      chan->wave->size,
-      false);
-
-    selectionA     = 0;
-    selectionB     = 0;
-    selectionA_abs = 0;
-    selectionB_abs = 0;
-
-    stretchToWindow();
-    menuOpen = false;
-    redraw();
-    return;
-  }
-
-  if (!strcmp(m->label(), "Fade in") || !strcmp(m->label(), "Fade out")) {
-
-    int type = !strcmp(m->label(), "Fade in") ? 0 : 1;
-    wfx_fade(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB), type);
-
-    selectionA = 0;
-    selectionB = 0;
-
-    stretchToWindow();
-    redraw();
-    menuOpen = false;
-    return;
-  }
-
-  if (!strcmp(m->label(), "Smooth edges")) {
-
-    wfx_smooth(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
-
-    selectionA = 0;
-    selectionB = 0;
-
-    stretchToWindow();
-    redraw();
-    menuOpen = false;
-    return;
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::straightSel() 
-{
-  if (selectionA > selectionB) {
-    unsigned tmp = selectionB;
-    selectionB = selectionA;
-    selectionA = tmp;
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::setZoom(int type) 
-{
-  int newSize;
-  if (type == -1) newSize = data.size*2;  // zoom in
-  else            newSize = data.size/2;  // zoom out
-
-  if (alloc(newSize)) {
-    size(data.size, h());
-
-    /* zoom to pointer */
-
-    int shift;
-    if (x() > 0)
-      shift = Fl::event_x() - x();
-    else
-    if (type == -1)
-      shift = Fl::event_x() + abs(x());
-    else
-      shift = (Fl::event_x() + abs(x())) / -2;
-
-    if (x() - shift > BORDER)
-      shift = 0;
-
-    position(x() - shift, y());
-
-
-    /* avoid overflow when zooming out with scrollbar like that:
-     * |----------[scrollbar]|
-     *
-     * offset vs smaller:
-     * |[wave------------| offset > 0  smaller = false
-     * |[wave----]       | offset < 0, smaller = true
-     * |-------------]   | offset < 0, smaller = false  */
-
-    int  parentW = ((gWaveTools*)parent())->w();
-    int  thisW   = x() + w() - BORDER;           // visible width, not full width
-
-    if (thisW < parentW)
-      position(x() + parentW - thisW, y());
-    if (smaller())
-      stretchToWindow();
-
-    redraw();
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::stretchToWindow() 
-{
-  int s = ((gWaveTools*)parent())->w();
-  alloc(s);
-  position(BORDER, y());
-  size(s, h());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gWaveform::smaller() 
-{
-  return w() < ((gWaveTools*)parent())->w();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveform::setGridLevel(int l)
-{
-  grid.points.clear();  
-  grid.level = l;
-  alloc(data.size);
-  redraw();
-}
diff --git a/src/ge_waveform.h b/src/ge_waveform.h
deleted file mode 100644 (file)
index 65c1e40..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_waveform
- * an element which represents a waveform.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GE_WAVEFORM_H
-#define GE_WAVEFORM_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Widget.H>
-#include <FL/fl_draw.H>
-#include <math.h>
-#include "utils.h"
-
-#define  FLAG_WIDTH  14
-#define  FLAG_HEIGHT 12
-#define  BORDER      8                         // window border <-> widget border
-
-
-class gWaveform : public Fl_Widget {
-
-private:
-
-       /* data
-        * real graphic stuff from the underlying waveform */
-       
-       struct data {
-               int *sup;
-               int *inf;
-               int  size;
-       } data;
-
-       /* grid */
-
-       struct grid {
-               bool snap;
-               int  level;
-               gVector<int> points;
-       } grid;
-
-       /* chan
-        * chan in use. */
-
-       class SampleChannel *chan;
-
-       /* menuOpen
-        * is the menu open? */
-
-       bool menuOpen;
-
-       /* mouseOnStart/end
-        * is mouse on start or end flag? */
-
-       bool mouseOnStart();
-       bool mouseOnEnd();
-
-       /* mouseOnSelectionA/B
-        * as above, for the selection */
-
-       bool mouseOnSelectionA();
-       bool mouseOnSelectionB();
-
-       /* absolutePoint
-        * from a relative 'p' point (zoom affected) returns the same point
-        * zoom 1:1 based */
-
-       int absolutePoint(int p);
-
-       /* relativePoint
-        * from an absolute 'p' point (1:1 zoom), returns the same point zoom
-        * affected */
-
-       int relativePoint(int p);
-
-       /* straightSel
-        * helper function which flattens the selection if it was made from
-        * right to left (inverse selection) */
-
-       void straightSel();
-
-       /* freeData
-        * destroy any graphical buffer */
-
-       void freeData();
-
-       /* smaller
-        * is the waveform smaller than the parent window? */
-
-       bool smaller();
-
-  /* applySnap
-   * snap a point at 'pos' pixel */
-
-  int applySnap(int pos);
-
-public:
-
-       gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0);
-       ~gWaveform();
-       void draw();
-       int  handle(int e);
-
-       /* alloc
-        * allocate memory for the picture */
-
-       int alloc(int datasize=0);
-
-       /* recalcPoints
-        * re-calc chanStart, chanEnd, ... */
-
-       void recalcPoints();
-
-       /* openEditMenu
-        * show edit menu on right-click */
-       
-       void openEditMenu();
-
-       /* displayRatio
-        * how much of the waveform is being displayed on screen */
-
-       inline float displayRatio() { return 1.0f / (data.size / (float) w()); };
-
-       /* zoom
-        * type == 1 : zoom out, type == -1: zoom in */
-
-       void setZoom(int type);
-
-       /* strecthToWindow
-        * shrink or enlarge the waveform to match parent's width (gWaveTools) */
-
-       void stretchToWindow();
-       
-       /* setGridLevel
-        * set a new frequency level for the grid. 0 means disabled. */
-
-       void setGridLevel(int l);
-
-  inline void setSnap(bool v) { grid.snap = v; }
-  inline bool getSnap()       { return grid.snap; }
-    
-       inline int getSize() { return data.size; }
-
-       int  chanStart;
-       bool chanStartLit;
-       int  chanEnd;
-       bool chanEndLit;
-       bool pushed;
-       bool dragged;
-       bool resized;
-
-       float ratio;
-  
-  /* TODO - useless! use Fl::mouse_x() and Fl::mouse_y() instead */
-       int  mouseX;                                     // mouse pos for drag.n.drop
-       int  mouseY;
-
-       /* selectionA/B  = portion of the selected wave
-        * " " "" " _abs = selectionA/B not affected by zoom */
-       /** TODO - change selectionA to selectionA_rel
-           TODO - change selectionB to selectionB_rel */
-       int selectionA;
-       int selectionB;
-       int selectionA_abs;
-       int selectionB_abs;
-};
-
-
-#endif
diff --git a/src/ge_window.cpp b/src/ge_window.cpp
deleted file mode 100644 (file)
index aba6fc0..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_window
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "ge_window.h"
-#include "log.h"
-
-
-gWindow::gWindow(int x, int y, int w, int h, const char *title, int id)
-       : Fl_Double_Window(x, y, w, h, title), id(id), parent(NULL) { }
-
-
-/* ------------------------------------------------------------------ */
-
-
-gWindow::gWindow(int w, int h, const char *title, int id)
-       : Fl_Double_Window(w, h, title), id(id), parent(NULL) { }
-
-
-/* ------------------------------------------------------------------ */
-
-
-gWindow::~gWindow() {
-
-       /* delete all subwindows in order to empty the stack */
-
-       for (unsigned i=0; i<subWindows.size; i++)
-               delete subWindows.at(i);
-       subWindows.clear();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-/* this is the default callback of each window, fired when the user closes
- * the window with the 'x'. Watch out: is the parent that calls delSubWIndow */
-
-void gWindow::cb_closeChild(Fl_Widget *v, void *p) {
-       gWindow *child = (gWindow*) v;
-       if (child->getParent() != NULL)
-               (child->getParent())->delSubWindow(child);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::addSubWindow(gWindow *w) {
-
-       /** TODO - useless: delete ---------------------------------------- */
-       for (unsigned i=0; i<subWindows.size; i++)
-               if (w->getId() == subWindows.at(i)->getId()) {
-                       //gLog("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId());
-                       delete w;
-                       return;
-               }
-       /** --------------------------------------------------------------- */
-
-       w->setParent(this);
-       w->callback(cb_closeChild); // you can pass params: w->callback(cb_closeChild, (void*)params)
-       subWindows.add(w);
-       //debug();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::delSubWindow(gWindow *w) {
-       for (unsigned i=0; i<subWindows.size; i++)
-               if (w->getId() == subWindows.at(i)->getId()) {
-                       delete subWindows.at(i);
-                       subWindows.del(i);
-                       //debug();
-                       return;
-               }
-       //debug();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::delSubWindow(int id) {
-       for (unsigned i=0; i<subWindows.size; i++)
-               if (subWindows.at(i)->getId() == id) {
-                       delete subWindows.at(i);
-                       subWindows.del(i);
-                       //debug();
-                       return;
-               }
-       //debug();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWindow::getId() {
-       return id;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::setId(int id) {
-       this->id = id;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::debug() {
-       gLog("---- window stack (id=%d): ----\n", getId());
-       for (unsigned i=0; i<subWindows.size; i++)
-               gLog("[gWindow] %p (id=%d)\n", (void*)subWindows.at(i), subWindows.at(i)->getId());
-       gLog("----\n");
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gWindow *gWindow::getParent() {
-       return parent;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWindow::setParent(gWindow *w) {
-       parent = w;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gWindow::hasWindow(int id) {
-       for (unsigned i=0; i<subWindows.size; i++)
-               if (id == subWindows.at(i)->getId())
-                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gWindow *gWindow::getChild(int id) {
-       for (unsigned i=0; i<subWindows.size; i++)
-               if (id == subWindows.at(i)->getId())
-                       return subWindows.at(i);
-       return NULL;
-}
diff --git a/src/ge_window.h b/src/ge_window.h
deleted file mode 100644 (file)
index 79d772e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_window
- * A custom window.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __GE_WINDOW_H__
-#define __GE_WINDOW_H__
-
-
-#include <FL/Fl_Double_Window.H>
-#include "utils.h"
-
-
-class gWindow : public Fl_Double_Window {
-
-protected:
-       gVector <gWindow *> subWindows;
-       int id;
-       gWindow *parent;
-
-public:
-       gWindow(int x, int y, int w, int h, const char *title=0, int id=0);
-       gWindow(int w, int h, const char *title=0, int id=0);
-       ~gWindow();
-
-       static void cb_closeChild(Fl_Widget *v, void *p);
-
-       void addSubWindow(gWindow *w);
-       void delSubWindow(gWindow *w);
-       void delSubWindow(int id);
-
-       int  getId();
-       void setId(int id);
-       void debug();
-
-       void     setParent(gWindow *);
-       gWindow *getParent();
-       gWindow *getChild(int id);
-
-       /* hasWindow
-        * true if the window with id 'id' exists in the stack. */
-
-       bool hasWindow(int id);
-
-};
-
-
-#endif
diff --git a/src/gg_keyboard.cpp b/src/gg_keyboard.cpp
deleted file mode 100644 (file)
index 8ea9be8..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gg_keyboard
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "gg_keyboard.h"
-#include "gd_browser.h"
-#include "gd_mainWindow.h"
-#include "gd_editor.h"
-#include "gd_warnings.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "mixer.h"
-#include "conf.h"
-#include "const.h"
-#include "glue.h"
-#include "patch.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "log.h"
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch                G_Patch;
-extern gdMainWindow *mainWin;
-
-
-int gKeyboard::indexColumn = 0;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gKeyboard::gKeyboard(int X, int Y, int W, int H)
-: Fl_Scroll    (X, Y, W, H),
-       bckspcPressed(false),
-       endPressed   (false),
-       spacePressed (false),
-       addColumnBtn (NULL)
-{
-       color(COLOR_BG_MAIN);
-       type(Fl_Scroll::BOTH_ALWAYS);
-       scrollbar.color(COLOR_BG_0);
-       scrollbar.selection_color(COLOR_BG_1);
-       scrollbar.labelcolor(COLOR_BD_1);
-       scrollbar.slider(G_BOX);
-       hscrollbar.color(COLOR_BG_0);
-       hscrollbar.selection_color(COLOR_BG_1);
-       hscrollbar.labelcolor(COLOR_BD_1);
-       hscrollbar.slider(G_BOX);
-
-       addColumnBtn = new gClick(8, y(), 200, 20, "Add new column");
-       addColumnBtn->callback(cb_addColumn, (void*) this);
-       add(addColumnBtn);
-
-       init();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::init()
-{
-       /* add 6 empty columns as init layout */
-
-       __cb_addColumn();
-       __cb_addColumn();
-       __cb_addColumn();
-       __cb_addColumn();
-       __cb_addColumn();
-       __cb_addColumn();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::freeChannel(gChannel *gch)
-{
-       gch->reset();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::deleteChannel(gChannel *gch)
-{
-       for (unsigned i=0; i<columns.size; i++) {
-               int k = columns.at(i)->find(gch);
-               if (k != columns.at(i)->children()) {
-                       columns.at(i)->deleteChannel(gch);
-                       return;
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::updateChannel(gChannel *gch)
-{
-       gch->update();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::organizeColumns()
-{
-       /* if only one column exists don't cleanup: the initial column must
-        * stay here. */
-
-       if (columns.size == 1)
-               return;
-
-       /* otherwise delete all empty columns */
-       /** FIXME - this for loop might not work correctly! */
-
-       for (unsigned i=columns.size-1; i>=1; i--) {
-               if (columns.at(i)->isEmpty()) {
-                       //Fl::delete_widget(columns.at(i));
-                       delete columns.at(i);
-                       columns.del(i);
-               }
-       }
-
-       /* compact column, avoid empty spaces */
-
-       for (unsigned i=1; i<columns.size; i++)
-               columns.at(i)->position(columns.at(i-1)->x() + columns.at(i-1)->w() + 16, y());
-
-       addColumnBtn->position(columns.last()->x() + columns.last()->w() + 16, y());
-
-       redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) { ((gKeyboard*)p)->__cb_addColumn(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build)
-{
-       gColumn *col = getColumn(colIndex);
-
-       /* no column with index 'colIndex' found? Just create it and set its index
-       to 'colIndex'. */
-
-       if (!col) {
-               __cb_addColumn();
-               col = columns.last();
-               col->setIndex(colIndex);
-               gLog("[gKeyboard::addChannel] created new column with index=%d\n", colIndex);
-       }
-
-       gLog("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
-       return col->addChannel(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::refreshColumns()
-{
-       for (unsigned i=0; i<columns.size; i++)
-               columns.at(i)->refreshChannels();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gColumn *gKeyboard::getColumn(int index)
-{
-       for (unsigned i=0; i<columns.size; i++)
-               if (columns.at(i)->getIndex() == index)
-                       return columns.at(i);
-       return NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gKeyboard::handle(int e)
-{
-       int ret = Fl_Group::handle(e);  // assume the buttons won't handle the Keyboard events
-       switch (e) {
-               case FL_FOCUS:
-               case FL_UNFOCUS: {
-                       ret = 1;                        // enables receiving Keyboard events
-                       break;
-               }
-               case FL_SHORTCUT:           // in case widget that isn't ours has focus
-               case FL_KEYDOWN:            // Keyboard key pushed
-               case FL_KEYUP: {            // Keyboard key released
-
-                       /* rewind session. Avoid retrigs */
-
-                       if (e == FL_KEYDOWN) {
-                               if (Fl::event_key() == FL_BackSpace && !bckspcPressed) {
-                                       bckspcPressed = true;
-                                       glue_rewindSeq();
-                                       ret = 1;
-                                       break;
-                               }
-                               else if (Fl::event_key() == FL_End && !endPressed) {
-                                       endPressed = true;
-                                       glue_startStopInputRec(false);  // update gui
-                                       ret = 1;
-                                       break;
-                               }
-                               else if (Fl::event_key() == FL_Enter && !enterPressed) {
-                                       enterPressed = true;
-                                       glue_startStopActionRec();
-                                       ret = 1;
-                                       break;
-                               }
-                               else if (Fl::event_key() == ' ' && !spacePressed) {
-                                       spacePressed = true;
-                                       G_Mixer.running ? glue_stopSeq() : glue_startSeq(); // TODO - glue_startStopSeq, no core logic here
-                                       ret = 1;
-                                       break;
-                               }
-                       }
-                       else if (e == FL_KEYUP) {
-                               if (Fl::event_key() == FL_BackSpace)
-                                       bckspcPressed = false;
-                               else if (Fl::event_key() == FL_End)
-                                       endPressed = false;
-                               else if (Fl::event_key() == ' ')
-                                       spacePressed = false;
-                               else if (Fl::event_key() == FL_Enter)
-                                       enterPressed = false;
-                       }
-
-                       /* Walk button arrays, trying to match button's label with the Keyboard event.
-                        * If found, set that button's value() based on up/down event,
-                        * and invoke that button's callback() */
-
-                       for (unsigned i=0; i<columns.size; i++)
-                               for (int k=1; k<columns.at(i)->children(); k++)
-                                       ret &= ((gChannel*)columns.at(i)->child(k))->keyPress(e);
-                       break;
-               }
-       }
-       return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::clear()
-{
-       for (unsigned i=0; i<columns.size; i++)
-               delete columns.at(i);
-       columns.clear();
-       indexColumn = 0;     // new columns will start from index=0
-       addColumnBtn->position(8, y());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::setChannelWithActions(gSampleChannel *gch)
-{
-       if (gch->ch->hasActions)
-               gch->addActionButton();
-       else
-               gch->delActionButton();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::printChannelMessage(int res)
-{
-       if      (res == SAMPLE_NOT_VALID)
-               gdAlert("This is not a valid WAVE file.");
-       else if (res == SAMPLE_MULTICHANNEL)
-               gdAlert("Multichannel samples not supported.");
-       else if (res == SAMPLE_WRONG_BIT)
-               gdAlert("This sample has an\nunsupported bit-depth (> 32 bit).");
-       else if (res == SAMPLE_WRONG_ENDIAN)
-               gdAlert("This sample has a wrong\nbyte order (not little-endian).");
-       else if (res == SAMPLE_WRONG_FORMAT)
-               gdAlert("This sample is encoded in\nan unsupported audio format.");
-       else if (res == SAMPLE_READ_ERROR)
-               gdAlert("Unable to read this sample.");
-       else if (res == SAMPLE_PATH_TOO_LONG)
-               gdAlert("File path too long.");
-       else
-               gdAlert("Unknown error.");
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void gKeyboard::__cb_addColumn()
-{
-       int colx;
-       int colxw;
-       int colw = 380;
-       if (columns.size == 0) {
-               colx  = x() - xposition();  // mind the offset with xposition()
-               colxw = colx + colw;
-       }
-       else {
-               gColumn *prev = columns.last();
-               colx  = prev->x()+prev->w() + 16;
-               colxw = colx + colw;
-       }
-
-       /* add gColumn to gKeyboard and to columns vector */
-
-       gColumn *gc = new gColumn(colx, y(), colw-20, 2000, indexColumn, this);
-  add(gc);
-       columns.add(gc);
-       indexColumn++;
-
-       /* move addColumn button */
-
-       addColumnBtn->position(colxw-4, y());
-       redraw();
-
-       gLog("[gKeyboard::__cb_addColumn] new column added (index = %d), total count=%d, addColumn(x)=%d\n",
-               gc->getIndex(), columns.size, addColumnBtn->x());
-}
diff --git a/src/gg_keyboard.h b/src/gg_keyboard.h
deleted file mode 100644 (file)
index 6059824..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gg_keyboard
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GG_KEYBOARD_H
-#define GG_KEYBOARD_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Group.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_column.h"
-#include "utils.h"
-
-
-class gKeyboard : public Fl_Scroll
-{
-private:
-
-       static void cb_addColumn  (Fl_Widget *v, void *p);
-       inline void __cb_addColumn();
-
-       bool bckspcPressed;
-       bool endPressed;
-       bool spacePressed;
-       bool enterPressed;
-
-       /* indexColumn
-        * the last index used for column. */
-
-       static int indexColumn;
-
-       class gClick *addColumnBtn;
-
-       /* columns
-        * a vector of columns which in turn contain channels. */
-
-       gVector<gColumn*> columns;
-
-public:
-
-       gKeyboard(int X, int Y, int W, int H);
-
-       int handle(int e);
-
-       /* init
-        * build the initial setup of empty channels. */
-
-       void init();
-
-       /* addChannel
-        * add a new channel to gChannels. Used by callbacks and during
-        * patch loading. Requires Channel (and not gChannel). If build is
-        * set to true, also generate the corresponding column.*/
-
-       gChannel *addChannel(int column, class Channel *ch, bool build=false);
-
-       /* deleteChannel
-        * delete a channel from gChannels<> where gChannel->ch == ch and remove
-        * it from the stack. */
-
-       void deleteChannel(gChannel *gch);
-
-       /* freeChannel
-        * free a channel from gChannels<> where gChannel->ch == ch. No channels
-        * are deleted */
-
-       void freeChannel(gChannel *gch);
-
-       /* updateChannel
-        * wrapper function to call gch->update(). */
-
-       void updateChannel(gChannel *gch);
-
-       /* organizeColumns
-        * reorganize columns layout by removing empty gaps. */
-
-       void organizeColumns();
-
-       /* refreshColumns
-        * refresh each column's channel, called on each GUI cycle. */
-
-       void refreshColumns();
-
-       /* getColumn
-        * return the column with index 'index', or NULL if not found. */
-
-       gColumn *getColumn(int index);
-
-       /* clear
-        * delete all channels and groups. */
-
-       void clear();
-
-       /* setChannelWithActions
-        * add 'R' button if channel has actions, and set recorder to active. */
-
-       void setChannelWithActions(class gSampleChannel *gch);
-
-       /* printChannelMessage
-        * given any output by glue_loadChannel, print the message on screen
-        * on a gdAlert subwindow. */
-
-       void printChannelMessage(int res);
-
-       /* getTotalColumns */
-
-       inline unsigned getTotalColumns() { return columns.size; }
-
-       /* getColumnWidth
-        * return the width in pixel of i-th column. Warning: 'i' is the i-th column
-        * in the column array, NOT the index. */
-
-       inline int getColumnWidth(int i) { return getColumn(i)->w(); }
-};
-
-
-#endif
diff --git a/src/gg_waveTools.cpp b/src/gg_waveTools.cpp
deleted file mode 100644 (file)
index d8462dd..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gg_waveTools
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "gg_waveTools.h"
-#include "graphics.h"
-#include "ge_mixed.h"
-#include "ge_waveform.h"
-#include "mixer.h"
-
-
-gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l)
-       : Fl_Scroll(x, y, w, h, l)
-{
-       type(Fl_Scroll::HORIZONTAL_ALWAYS);
-       hscrollbar.color(COLOR_BG_0);
-       hscrollbar.selection_color(COLOR_BG_1);
-       hscrollbar.labelcolor(COLOR_BD_1);
-       hscrollbar.slider(G_BOX);
-
-       waveform = new gWaveform(x, y, w, h-24, ch);
-
-
-       //resizable(waveform);
-}
-
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveTools::updateWaveform() 
-{
-       waveform->alloc(w());
-       waveform->redraw();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gWaveTools::resize(int x, int y, int w, int h) 
-{
-       if (this->w() == w || (this->w() != w && this->h() != h)) {   // vertical or both resize
-               Fl_Widget::resize(x, y, w, h);
-               waveform->resize(x, y, waveform->w(), h-24);
-               updateWaveform();
-       }
-       else {                                                        // horizontal resize
-               Fl_Widget::resize(x, y, w, h);
-       }
-
-       if (this->w() > waveform->w())
-               waveform->stretchToWindow();
-
-       int offset = waveform->x() + waveform->w() - this->w() - this->x();
-       if (offset < 0)
-               waveform->position(waveform->x()-offset, this->y());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gWaveTools::handle(int e) 
-{
-       int ret = Fl_Group::handle(e);
-       switch (e) {
-               case FL_MOUSEWHEEL: {
-                       waveform->setZoom(Fl::event_dy());
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
diff --git a/src/gg_waveTools.h b/src/gg_waveTools.h
deleted file mode 100644 (file)
index 8f81ba1..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gg_waveTools
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GG_WAVETOOLS_H
-#define GG_WAVETOOLS_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include <FL/Fl_Scroll.H>
-
-
-class gWaveTools : public Fl_Scroll {
-public:
-       class gWaveform *waveform;
-
-       gWaveTools(int X,int Y,int W, int H, class SampleChannel *ch, const char *L=0);
-       void resize(int x, int y, int w, int h);
-       int  handle(int e);
-
-       void updateWaveform();
-};
-
-#endif
diff --git a/src/giada.ico b/src/giada.ico
deleted file mode 100644 (file)
index e0a90bd..0000000
Binary files a/src/giada.ico and /dev/null differ
diff --git a/src/glue.cpp b/src/glue.cpp
deleted file mode 100644 (file)
index 60d0a17..0000000
+++ /dev/null
@@ -1,1189 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * glue
- * Intermediate layer GUI <-> CORE.
- *
- * How to know if you need another glue_ function? Ask yourself if the
- * new action will ever be called via MIDI or keyboard/mouse. If yes,
- * put it here.
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "glue.h"
-#include "ge_waveform.h"
-#include "gd_mainWindow.h"
-#include "gd_editor.h"
-#include "gd_warnings.h"
-#include "gg_waveTools.h"
-#include "ge_mixed.h"
-#include "gg_keyboard.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "gui_utils.h"
-#include "mixerHandler.h"
-#include "mixer.h"
-#include "recorder.h"
-#include "wave.h"
-#include "pluginHost.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "utils.h"
-#include "kernelMidi.h"
-#include "log.h"
-#include "patch.h"
-#include "conf.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer                    G_Mixer;
-extern Patch                    G_Patch;
-extern Conf                             G_Conf;
-extern bool                             G_audio_status;
-#ifdef WITH_VST
-extern PluginHost               G_PluginHost;
-#endif
-
-
-static bool __soloSession__ = false;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_loadChannel(SampleChannel *ch, const char *fname)
-{
-       /* save the patch and take the last browser's dir in order to re-use it
-        * the next time */
-
-       G_Conf.setPath(G_Conf.samplePath, gDirname(fname).c_str());
-
-       int result = ch->load(fname);
-
-       if (result == SAMPLE_LOADED_OK)
-               mainWin->keyboard->updateChannel(ch->guiChannel);
-
-       return result;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Channel *glue_addChannel(int column, int type)
-{
-       Channel *ch    = G_Mixer.addChannel(type);
-       gChannel *gch  = mainWin->keyboard->addChannel(column, ch);
-       ch->guiChannel = gch;
-       glue_setChanVol(ch, 1.0, false); // false = not from gui click
-       return ch;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_loadPatch(const char *fname, const char *fpath, gProgress *status, bool isProject)
-{
-       /* update browser's status bar with % 0.1 */
-
-       status->show();
-       status->value(0.1f);
-       //Fl::check();
-       Fl::wait(0);
-
-       /* is it a valid patch? */
-
-       int res = G_Patch.open(fname);
-       if (res != PATCH_OPEN_OK)
-               return res;
-
-       /* close all other windows. This prevents segfault if plugin windows
-        * GUI are on. */
-
-       if (res)
-               gu_closeAllSubwindows();
-
-       /* reset the system. False(1): don't update the gui right now. False(2): do
-        * not create empty columns. */
-
-       glue_resetToInitState(false, false);
-
-       status->value(0.2f);  // progress status: % 0.2
-       //Fl::check();
-       Fl::wait(0);
-
-       /* mixerHandler will update the samples inside Mixer */
-
-       mh_loadPatch(isProject, fname);
-
-       /* take the patch name and update the main window's title */
-
-       G_Patch.getName();
-       gu_update_win_label(G_Patch.name);
-
-       status->value(0.4f);  // progress status: 0.4
-       //Fl::check();
-       Fl::wait(0);
-
-       G_Patch.readRecs();
-       status->value(0.6f);  // progress status: 0.6
-       //Fl::check();
-       Fl::wait(0);
-
-#ifdef WITH_VST
-       int resPlugins = G_Patch.readPlugins();
-       status->value(0.8f);  // progress status: 0.8
-       //Fl::check();
-       Fl::wait(0);
-#endif
-
-       /* this one is vital: let recorder recompute the actions' positions if
-        * the current samplerate != patch samplerate */
-
-       recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate);
-
-       /* update gui */
-
-       gu_updateControls();
-
-       status->value(1.0f);  // progress status: 1.0 (done)
-       //Fl::check();
-       Fl::wait(0);
-
-       /* save patchPath by taking the last dir of the broswer, in order to
-        * reuse it the next time */
-
-       G_Conf.setPath(G_Conf.patchPath, fpath);
-
-       gLog("[glue] patch %s loaded\n", fname);
-
-#ifdef WITH_VST
-       if (resPlugins != 1)
-               gdAlert("Some VST plugins were not loaded successfully.");
-#endif
-
-       return res;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_savePatch(const char *fullpath, const char *name, bool isProject)
-{
-       if (G_Patch.write(fullpath, name, isProject) == 1) {
-               strcpy(G_Patch.name, name);
-               G_Patch.name[strlen(name)] = '\0';
-               gu_update_win_label(name);
-               gLog("[glue] patch saved as %s\n", fullpath);
-               return 1;
-       }
-       else
-               return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_deleteChannel(Channel *ch)
-{
-       int index = ch->index;
-       recorder::clearChan(index);
-       Fl::lock();
-       mainWin->keyboard->deleteChannel(ch->guiChannel);
-       Fl::unlock();
-       G_Mixer.deleteChannel(ch);
-       gu_closeAllSubwindows();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_freeChannel(Channel *ch)
-{
-       mainWin->keyboard->freeChannel(ch->guiChannel);
-       recorder::clearChan(ch->index);
-       ch->empty();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBpm(const char *v1, const char *v2)
-{
-       char  buf[6];
-       float value = atof(v1) + (atof(v2)/10);
-       if (value < 20.0f)      {
-               value = 20.0f;
-               sprintf(buf, "20.0");
-       }
-       else
-               sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2);
-
-       /* a value such as atof("120.1") will never be 120.1 but 120.0999999,
-        * because of the rounding error. So we pass the real "wrong" value to
-        * G_Mixer and we show the nice looking (but fake) one to the GUI. */
-
-       float old_bpm = G_Mixer.bpm;
-       G_Mixer.bpm = value;
-       G_Mixer.updateFrameBars();
-
-       /* inform recorder and actionEditor of the change */
-
-       recorder::updateBpm(old_bpm, value, G_Mixer.quanto);
-       gu_refreshActionEditor();
-
-       mainWin->timing->setBpm(buf);
-       gLog("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBeats(int beats, int bars, bool expand)
-{
-       /* temp vars to store old data (they are necessary) */
-
-       int      oldvalue = G_Mixer.beats;
-       unsigned oldfpb         = G_Mixer.totalFrames;
-
-       if (beats > MAX_BEATS)
-               G_Mixer.beats = MAX_BEATS;
-       else if (beats < 1)
-               G_Mixer.beats = 1;
-       else
-               G_Mixer.beats = beats;
-
-       /* update bars - bars cannot be greate than beats and must be a sub
-        * multiple of beats. If not, approximation to the nearest (and greater)
-        * value available. */
-
-       if (bars > G_Mixer.beats)
-               G_Mixer.bars = G_Mixer.beats;
-       else if (bars <= 0)
-               G_Mixer.bars = 1;
-       else if (beats % bars != 0) {
-               G_Mixer.bars = bars + (beats % bars);
-               if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it)
-                       G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars);
-       }
-       else
-               G_Mixer.bars = bars;
-
-       G_Mixer.updateFrameBars();
-
-       /* update recorded actions */
-
-       if (expand) {
-               if (G_Mixer.beats > oldvalue)
-                       recorder::expand(oldfpb, G_Mixer.totalFrames);
-               //else if (G_Mixer.beats < oldvalue)
-               //      recorder::shrink(G_Mixer.totalFrames);
-       }
-
-       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
-       gu_refreshActionEditor();  // in case the action editor is open
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopSeq(bool gui)
-{
-       G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startSeq(bool gui)
-{
-       G_Mixer.running = true;
-
-       if (gui) {
-#ifdef __linux__
-               kernelAudio::jackStart();
-#endif
-       }
-
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
-               kernelMidi::send(MIDI_START, -1, -1);
-               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
-       }
-
-       if (gui) Fl::lock();
-       mainWin->controller->updatePlay(1);
-       if (gui) Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopSeq(bool gui) {
-
-       mh_stopSequencer();
-
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
-               kernelMidi::send(MIDI_STOP, -1, -1);
-
-#ifdef __linux__
-       if (gui)
-               kernelAudio::jackStop();
-#endif
-
-       /* what to do if we stop the sequencer and some action recs are active?
-        * Deactivate the button and delete any 'rec on' status */
-
-       if (recorder::active) {
-               recorder::active = false;
-               if (gui) Fl::lock();
-               mainWin->controller->updateRecAction(0);
-               if (gui) Fl::unlock();
-       }
-
-       /* if input recs are active (who knows why) we must deactivate them.
-        * One might stop the sequencer while an input rec is running. */
-
-       if (G_Mixer.chanInput != NULL) {
-               mh_stopInputRec();
-               if (gui) Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               if (gui) Fl::unlock();
-       }
-
-       if (gui) Fl::lock();
-       mainWin->controller->updatePlay(0);
-       if (gui) Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_rewindSeq() {
-       mh_rewindSequencer();
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
-               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopActionRec() {
-       recorder::active ? glue_stopActionRec() : glue_startActionRec();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startActionRec() {
-       if (G_audio_status == false)
-               return;
-       if (!G_Mixer.running)
-               glue_startSeq();                // start the sequencer for convenience
-       recorder::active = true;
-
-       Fl::lock();
-       mainWin->controller->updateRecAction(1);
-       Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopActionRec() {
-
-       /* stop the recorder and sort new actions */
-
-       recorder::active = false;
-       recorder::sortActions();
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
-                       SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
-                       if (ch->hasActions)
-                               ch->readActions = true;
-                       else
-                               ch->readActions = false;
-                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel);
-               }
-
-       Fl::lock();
-       mainWin->controller->updateRecAction(0);
-       Fl::unlock();
-
-       /* in case acton editor is on, refresh it */
-
-       gu_refreshActionEditor();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopReadingRecs(SampleChannel *ch, bool gui) {
-       if (ch->readActions)
-               glue_stopReadingRecs(ch, gui);
-       else
-               glue_startReadingRecs(ch, gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startReadingRecs(SampleChannel *ch, bool gui) {
-       if (G_Conf.treatRecsAsLoops)
-               ch->recStatus = REC_WAITING;
-       else
-               ch->setReadActions(true);
-       if (!gui) {
-               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
-               if (gch->readActions) { // if button exists
-                       Fl::lock();
-                       gch->readActions->value(1);
-                       Fl::unlock();
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopReadingRecs(SampleChannel *ch, bool gui) {
-
-       /* if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put
-        * the channel in REC_ENDING status */
-
-       if (G_Conf.treatRecsAsLoops)
-               ch->recStatus = REC_ENDING;
-       else
-               ch->setReadActions(false);
-       if (!gui) {
-               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
-               if (gch->readActions) {  // if button exists
-                       Fl::lock();
-                       gch->readActions->value(0);
-                       Fl::unlock();
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_quantize(int val) {
-       G_Mixer.quantize = val;
-       G_Mixer.updateQuanto();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setChanVol(Channel *ch, float v, bool gui) {
-
-       ch->volume = v;
-
-       /* also update wave editor if it's shown */
-
-       gdEditor *editor = (gdEditor*) gu_getSubwindow(mainWin, WID_SAMPLE_EDITOR);
-       if (editor) {
-               glue_setVolEditor(editor, (SampleChannel*) ch, v, false);
-               Fl::lock();
-               editor->volume->value(v);
-               Fl::unlock();
-       }
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->vol->value(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setOutVol(float v, bool gui) {
-       G_Mixer.outVol = v;
-       if (!gui) {
-               Fl::lock();
-               mainWin->inOut->setOutVol(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setInVol(float v, bool gui)
-{
-       G_Mixer.inVol = v;
-       if (!gui) {
-               Fl::lock();
-               mainWin->inOut->setInVol(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_clearAllSamples()
-{
-       G_Mixer.running = false;
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               G_Mixer.channels.at(i)->empty();
-               G_Mixer.channels.at(i)->guiChannel->reset();
-       }
-       recorder::init();
-       return;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_clearAllRecs()
-{
-       recorder::init();
-       gu_updateControls();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_resetToInitState(bool resetGui, bool createColumns)
-{
-       G_Mixer.ready = false;
-
-       mh_clear();
-       mainWin->keyboard->clear();
-       if (createColumns)
-               mainWin->keyboard->init();
-       recorder::init();
-       G_Patch.setDefault();
-       G_Mixer.init();
-#ifdef WITH_VST
-       G_PluginHost.freeAllStacks();
-#endif
-
-       if (resetGui)
-               gu_updateControls();
-
-       G_Mixer.ready = true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopMetronome(bool gui)
-{
-       G_Mixer.metronome = !G_Mixer.metronome;
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateMetronome(G_Mixer.metronome);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, bool recalc, bool check)
-{
-       if (check) {
-               if (e > ch->wave->size)
-                       e = ch->wave->size;
-               if (b < 0)
-                       b = 0;
-               if (b > ch->wave->size)
-                       b = ch->wave->size-2;
-               if (b >= ch->end)
-                       b = ch->begin;
-               if (e <= ch->begin)
-                       e = ch->end;
-       }
-
-       /* continue only if new values != old values */
-
-       if (b == ch->begin && e == ch->end)
-               return;
-
-       /* print mono values */
-
-       char tmp[16];
-       sprintf(tmp, "%d", b/2);
-       win->chanStart->value(tmp);
-
-       tmp[0] = '\0';
-       sprintf(tmp, "%d", e/2);
-       win->chanEnd->value(tmp);
-
-       ch->setBegin(b);
-       ch->setEnd(e);
-
-       /* recalc is not needed when the user drags the bars directly over the waveform */
-
-       if (recalc) {
-               win->waveTools->waveform->recalcPoints();       // importante, altrimenti non si vedono
-               win->waveTools->waveform->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val > 20.0f)
-                       val = 20.0f;
-               else if (val < 0.0f)
-                       val = 0.0f;
-
-         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
-
-               ch->boost = linear;
-
-               char buf[10];
-               sprintf(buf, "%.2f", val);
-               win->boostNum->value(buf);
-               win->boostNum->redraw();
-
-               win->boost->value(linear);
-               win->boost->redraw();       /// inutile
-       }
-       else {
-               ch->boost = val;
-               char buf[10];
-               sprintf(buf, "%.2f", 20*log10(val));
-               win->boostNum->value(buf);
-               win->boostNum->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val > 0.0f)
-                       val = 0.0f;
-               else if (val < -60.0f)
-                       val = -INFINITY;
-
-         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
-
-               ch->volume = linear;
-
-               win->volume->value(linear);
-               win->volume->redraw();
-
-               char buf[10];
-               if (val > -INFINITY)
-                       sprintf(buf, "%.2f", val);
-               else
-                       sprintf(buf, "-inf");
-               win->volumeNum->value(buf);
-               win->volumeNum->redraw();
-
-               ch->guiChannel->vol->value(linear);
-               ch->guiChannel->vol->redraw();
-       }
-       else {
-               ch->volume = val;
-
-               float dbVal = 20 * log10(val);
-               char buf[10];
-               if (dbVal > -INFINITY)
-                       sprintf(buf, "%.2f", dbVal);
-               else
-                       sprintf(buf, "-inf");
-
-               win->volumeNum->value(buf);
-               win->volumeNum->redraw();
-
-               ch->guiChannel->vol->value(val);
-               ch->guiChannel->vol->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setMute(Channel *ch, bool gui)
-{
-       if (recorder::active && recorder::canRec(ch)) {
-               if (!ch->mute)
-                       recorder::startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame);
-               else
-                recorder::stopOverdub(G_Mixer.actualFrame);
-       }
-
-       ch->mute ? ch->unsetMute(false) : ch->setMute(false);
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->mute->value(ch->mute);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setSoloOn(Channel *ch, bool gui)
-{
-       /* if there's no solo session, store mute configuration of all chans
-        * and start the session */
-
-       if (!__soloSession__) {
-               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-                       Channel *och = G_Mixer.channels.at(i);
-                       och->mute_s  = och->mute;
-               }
-               __soloSession__ = true;
-       }
-
-       ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       /* mute all other channels and unmute this (if muted) */
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               Channel *och = G_Mixer.channels.at(i);
-               if (!och->solo && !och->mute) {
-                       och->setMute(false);
-                       Fl::lock();
-                       och->guiChannel->mute->value(true);
-                       Fl::unlock();
-               }
-       }
-
-       if (ch->mute) {
-               ch->unsetMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(false);
-               Fl::unlock();
-       }
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->solo->value(1);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setSoloOff(Channel *ch, bool gui)
-{
-       /* if this is uniqueSolo, stop solo session and restore mute status,
-        * else mute this */
-
-       if (mh_uniqueSolo(ch)) {
-               __soloSession__ = false;
-               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-                       Channel *och = G_Mixer.channels.at(i);
-                       if (och->mute_s) {
-                               och->setMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(true);
-                               Fl::unlock();
-                       }
-                       else {
-                               och->unsetMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(false);
-                               Fl::unlock();
-                       }
-                       och->mute_s = false;
-               }
-       }
-       else {
-               ch->setMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(true);
-               Fl::unlock();
-       }
-
-       ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->solo->value(0);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val)
-{
-       if (val < 1.0f) {
-               ch->panLeft = 1.0f;
-               ch->panRight= 0.0f + val;
-
-               char buf[8];
-               sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100));
-               win->panNum->value(buf);
-       }
-       else if (val == 1.0f) {
-               ch->panLeft = 1.0f;
-               ch->panRight= 1.0f;
-         win->panNum->value("C");
-       }
-       else {
-               ch->panLeft = 2.0f - val;
-               ch->panRight= 1.0f;
-
-               char buf[8];
-               sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100));
-               win->panNum->value(buf);
-       }
-       win->panNum->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopInputRec(bool gui, bool alert)
-{
-       if (G_Mixer.chanInput == NULL) {
-               if (!glue_startInputRec(gui)) {
-                       if (alert) gdAlert("No channels available for recording.");
-                       else       gLog("[glue] no channels available for recording\n");
-               }
-       }
-       else
-               glue_stopInputRec(gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_startInputRec(bool gui)
-{
-       if (G_audio_status == false)
-               return -1;
-
-       SampleChannel *ch = mh_startInputRec();
-       if (ch == NULL) {                  // no chans available
-               Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               Fl::unlock();
-               return 0;
-       }
-
-       if (!G_Mixer.running) {
-               glue_startSeq();
-               Fl::lock();
-               mainWin->controller->updatePlay(1);
-               Fl::unlock();
-       }
-
-       glue_setChanVol(ch, 1.0f, false); // false = not from gui click
-
-       ch->guiChannel->mainButton->label(ch->wave->name.c_str());
-
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateRecInput(1);
-               Fl::unlock();
-       }
-
-       return 1;
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_stopInputRec(bool gui)
-{
-       SampleChannel *ch = mh_stopInputRec();
-
-       if (ch->mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT))
-               ch->start(0, true);  // on frame 0: user-generated event
-
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               Fl::unlock();
-       }
-
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_saveProject(const char *folderPath, const char *projName)
-{
-       if (gIsProject(folderPath)) {
-               gLog("[glue] the project folder already exists\n");
-               // don't exit
-       }
-       else if (!gMkdir(folderPath)) {
-               gLog("[glue] unable to make project directory!\n");
-               return 0;
-       }
-
-       /* copy all samples inside the folder. Takes and logical ones are saved
-        * via glue_saveSample() */
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
-
-                       SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
-
-                       if (ch->wave == NULL)
-                               continue;
-
-                       /* update the new samplePath: everything now comes from the
-                        * project folder (folderPath) */
-
-                       char samplePath[PATH_MAX];
-                       sprintf(samplePath, "%s%s%s.%s", folderPath, gGetSlash().c_str(), ch->wave->basename().c_str(), ch->wave->extension().c_str());
-
-                       /* remove any existing file */
-
-                       if (gFileExists(samplePath))
-                               remove(samplePath);
-                       if (ch->save(samplePath))
-                               ch->wave->pathfile = samplePath;
-               }
-       }
-
-       char gptcPath[PATH_MAX];
-       sprintf(gptcPath, "%s%s%s.gptc", folderPath, gGetSlash().c_str(), gStripExt(projName).c_str());
-       glue_savePatch(gptcPath, projName, true); // true == it's a project
-
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(Channel *ch, bool ctrl, bool shift)
-{
-       if (ch->type == CHANNEL_SAMPLE)
-               glue_keyPress((SampleChannel*)ch, ctrl, shift);
-       else
-               glue_keyPress((MidiChannel*)ch, ctrl, shift);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyRelease(Channel *ch, bool ctrl, bool shift)
-{
-       if (ch->type == CHANNEL_SAMPLE)
-               glue_keyRelease((SampleChannel*)ch, ctrl, shift);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift)
-{
-       if (ctrl)
-               glue_setMute(ch);
-       else
-       if (shift)
-               ch->kill(0);        // on frame 0: user-generated event
-       else
-               ch->start(0, true); // on frame 0: user-generated event
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift)
-{
-       /* case CTRL */
-
-       if (ctrl)
-               glue_setMute(ch);
-
-       /* case SHIFT
-        *
-        * action recording on:
-        *              if seq is playing, rec a killchan
-        * action recording off:
-        *              if chan has recorded events:
-        *              |        if seq is playing OR channel 'c' is stopped, de/activate recs
-        *              |        else kill chan
-        *              else kill chan */
-
-       else
-       if (shift) {
-               if (recorder::active) {
-                       if (G_Mixer.running) {
-                               ch->kill(0); // on frame 0: user-generated event
-                               if (recorder::canRec(ch) && !(ch->mode & LOOP_ANY))   // don't record killChan actions for LOOP channels
-                                       recorder::rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame);
-                       }
-               }
-               else {
-                       if (ch->hasActions) {
-                               if (G_Mixer.running || ch->status == STATUS_OFF)
-                                       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
-                               else
-                                       ch->kill(0);  // on frame 0: user-generated event
-                       }
-                       else
-                               ch->kill(0);    // on frame 0: user-generated event
-               }
-       }
-
-       /* case no modifier */
-
-       else {
-
-               /* record now if the quantizer is off, otherwise let mixer to handle it
-                * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are
-                * meaningless for loop modes */
-
-               if (G_Mixer.quantize == 0 &&
-                   recorder::canRec(ch)  &&
-             !(ch->mode & LOOP_ANY))
-               {
-                       if (ch->mode == SINGLE_PRESS)
-                               recorder::startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame);
-                       else
-                               recorder::rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame);
-               }
-
-               ch->start(0, true); // on frame 0: user-generated event
-       }
-
-       /* the GUI update is done by gui_refresh() */
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift)
-{
-       if (!ctrl && !shift) {
-               ch->stop();
-
-               /* record a key release only if channel is single_press. For any
-                * other mode the KEY REL is meaningless. */
-
-               if (ch->mode == SINGLE_PRESS && recorder::canRec(ch))
-                       recorder::stopOverdub(G_Mixer.actualFrame);
-       }
-
-       /* the GUI update is done by gui_refresh() */
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setPitch(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val <= 0.0f)
-                       val = 0.1000f;
-               if (val > 4.0f)
-                       val = 4.0000f;
-               if (win)
-                       win->pitch->value(val);
-       }
-
-       ch->setPitch(val);
-
-       if (win) {
-               char buf[16];
-               sprintf(buf, "%.4f", val);
-               Fl::lock();
-               win->pitchNum->value(buf);
-               win->pitchNum->redraw();
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* never expand or shrink recordings (last param of setBeats = false):
- * this is live manipulation */
-
-void glue_beatsMultiply()
-{
-       glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false);
-}
-
-void glue_beatsDivide()
-{
-       glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false);
-}
diff --git a/src/glue.h b/src/glue.h
deleted file mode 100644 (file)
index d018a6c..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * glue
- * Intermediate layer GUI <-> CORE.
- *
- * How to know if you need another glue_ function? Ask yourself if the
- * new action will ever be called via MIDI or keyboard/mouse. If yes,
- * put it here.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GLUE_H
-#define GLUE_H
-
-/* addChannel
- * add an empty new channel to the stack. Returns the new channel. */
-
-class Channel *glue_addChannel(int column, int type);
-
-/* loadChannel
- * fill an existing channel with a wave. */
-
-int glue_loadChannel(class SampleChannel *ch, const char *fname);
-
-void glue_deleteChannel(class Channel *ch);
-
-void glue_freeChannel(class Channel *ch);
-
-/** FIXME - nobody will call these via MIDI/keyb/mouse! */
-int glue_loadPatch(const char *fname, const char *fpath, class gProgress *status, bool isProject);
-int glue_savePatch(const char *fullpath, const char *name, bool isProject);
-
-/* keyPress / keyRelease
- * handle the key pressure, either via mouse/keyboard or MIDI. If gui
- * is true it means that the event comes from the main window (mouse,
- * keyb or MIDI), otherwise the event comes from the action recorder. */
-
-void glue_keyPress  (class Channel       *ch, bool ctrl=0, bool shift=0);
-void glue_keyPress  (class SampleChannel *ch, bool ctrl=0, bool shift=0);
-void glue_keyPress  (class MidiChannel   *ch, bool ctrl=0, bool shift=0);
-void glue_keyRelease(class Channel       *ch, bool ctrl=0, bool shift=0);
-void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0);
-
-void glue_setBpm(const char *v1, const char *v2);
-void glue_setBeats(int beats, int bars, bool expand);
-
-/* start, stop, rewind sequencer
- * if gui == true the signal comes from an internal interaction on the
- * GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_startStopSeq(bool gui=true);
-void glue_startSeq    (bool gui=true);
-void glue_stopSeq     (bool gui=true);
-void glue_rewindSeq   ();
-
-/* start/stopActionRec
- * handle the action recording. */
-
-void glue_startStopActionRec();
-void glue_startActionRec();
-void glue_stopActionRec();
-
-/* start/stopInputRec
- * handle the input recording (take). If gui == true the signal comes
- * from an internal interaction on the GUI, otherwise it's a
- * MIDI/Jack/external signal. Alert displays or not the popup message
- * if there are no available channels. */
-
-void glue_startStopInputRec(bool gui=true, bool alert=true);
-int  glue_startInputRec    (bool gui=true);
-int  glue_stopInputRec     (bool gui=true);
-
-/* start/stopReadingRecs
- * handle the 'R' button. If gui == true the signal comes from an
- * internal interaction on the GUI, otherwise it's a MIDI/Jack/external
- * signal. */
-
-void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true);
-void glue_startReadingRecs    (class SampleChannel *ch, bool gui=true);
-void glue_stopReadingRecs     (class SampleChannel *ch, bool gui=true);
-
-void glue_quantize(int val);
-
-void glue_setChanVol(class Channel *ch, float v, bool gui=true);
-void glue_setOutVol (float v, bool gui=true);
-void glue_setInVol  (float v, bool gui=true);
-
-void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val);
-
-void glue_clearAllSamples();
-void glue_clearAllRecs();
-
-/* resetToInitState
- * reset Giada to init state. If resetGui also refresh all widgets. If
- * createColumns also build initial empty columns. */
-
-void glue_resetToInitState(bool resetGui=true, bool createColumns=true);
-
-void glue_startStopMetronome(bool gui=true);
-
-/* setBeginEndChannel
- * sets start/end points in the sample editor.
- * Recalc=false: don't recalc internal position
- * check=true: check the points' consistency */
-
-/** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, int b, int e,
-                                                                                                                bool recalc=false, bool check=true);
-
-/** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-/* setVolEditor
- * handles the volume inside the SAMPLE EDITOR (not the main gui). The
- * numeric flag tells if we want to handle the dial or the numeric input
- * field. */
-
- /** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-/* mute
- * set mute on or off. If gui == true the signal comes from an internal
- * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_setMute(class Channel *ch, bool gui=true);
-
-/* solo on/off
- * set solo on and off. If gui == true the signal comes from an internal
- * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_setSoloOn (class Channel *ch, bool gui=true);
-void glue_setSoloOff(class Channel *ch, bool gui=true);
-
-/** FIXME - nobody will call this via MIDI/keyb/mouse! */
-int glue_saveProject(const char *folderPath, const char *projName);
-
-
-/* beatsDivide/Multiply
- * shrinks or enlarges the number of beats by 2. */
-
-void glue_beatsMultiply();
-void glue_beatsDivide();
-
-#endif
diff --git a/src/glue/glue.cpp b/src/glue/glue.cpp
new file mode 100644 (file)
index 0000000..c2ec2c5
--- /dev/null
@@ -0,0 +1,1189 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../gui/elems/ge_waveform.h"
+#include "../gui/elems/ge_mixed.h"
+#include "../gui/elems/ge_channel.h"
+#include "../gui/elems/ge_sampleChannel.h"
+#include "../gui/elems/ge_waveTools.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_editor.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../utils/gui_utils.h"
+#include "../utils/utils.h"
+#include "../utils/log.h"
+#include "../core/mixerHandler.h"
+#include "../core/mixer.h"
+#include "../core/recorder.h"
+#include "../core/wave.h"
+#include "../core/pluginHost.h"
+#include "../core/channel.h"
+#include "../core/sampleChannel.h"
+#include "../core/midiChannel.h"
+#include "../core/kernelMidi.h"
+#include "../core/patch.h"
+#include "../core/conf.h"
+#include "glue.h"
+
+
+extern gdMainWindow *mainWin;
+extern Mixer                    G_Mixer;
+extern Patch                    G_Patch;
+extern Conf                             G_Conf;
+extern bool                             G_audio_status;
+#ifdef WITH_VST
+extern PluginHost               G_PluginHost;
+#endif
+
+
+static bool __soloSession__ = false;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_loadChannel(SampleChannel *ch, const char *fname)
+{
+       /* save the patch and take the last browser's dir in order to re-use it
+        * the next time */
+
+       G_Conf.setPath(G_Conf.samplePath, gDirname(fname).c_str());
+
+       int result = ch->load(fname);
+
+       if (result == SAMPLE_LOADED_OK)
+               mainWin->keyboard->updateChannel(ch->guiChannel);
+
+       return result;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+Channel *glue_addChannel(int column, int type)
+{
+       Channel *ch    = G_Mixer.addChannel(type);
+       gChannel *gch  = mainWin->keyboard->addChannel(column, ch);
+       ch->guiChannel = gch;
+       glue_setChanVol(ch, 1.0, false); // false = not from gui click
+       return ch;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_loadPatch(const char *fname, const char *fpath, gProgress *status, bool isProject)
+{
+       /* update browser's status bar with % 0.1 */
+
+       status->show();
+       status->value(0.1f);
+       //Fl::check();
+       Fl::wait(0);
+
+       /* is it a valid patch? */
+
+       int res = G_Patch.open(fname);
+       if (res != PATCH_OPEN_OK)
+               return res;
+
+       /* close all other windows. This prevents segfault if plugin windows
+        * GUI are on. */
+
+       if (res)
+               gu_closeAllSubwindows();
+
+       /* reset the system. False(1): don't update the gui right now. False(2): do
+        * not create empty columns. */
+
+       glue_resetToInitState(false, false);
+
+       status->value(0.2f);  // progress status: % 0.2
+       //Fl::check();
+       Fl::wait(0);
+
+       /* mixerHandler will update the samples inside Mixer */
+
+       mh_loadPatch(isProject, fname);
+
+       /* take the patch name and update the main window's title */
+
+       G_Patch.getName();
+       gu_update_win_label(G_Patch.name);
+
+       status->value(0.4f);  // progress status: 0.4
+       //Fl::check();
+       Fl::wait(0);
+
+       G_Patch.readRecs();
+       status->value(0.6f);  // progress status: 0.6
+       //Fl::check();
+       Fl::wait(0);
+
+#ifdef WITH_VST
+       int resPlugins = G_Patch.readPlugins();
+       status->value(0.8f);  // progress status: 0.8
+       //Fl::check();
+       Fl::wait(0);
+#endif
+
+       /* this one is vital: let recorder recompute the actions' positions if
+        * the current samplerate != patch samplerate */
+
+       recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate);
+
+       /* update gui */
+
+       gu_updateControls();
+
+       status->value(1.0f);  // progress status: 1.0 (done)
+       //Fl::check();
+       Fl::wait(0);
+
+       /* save patchPath by taking the last dir of the broswer, in order to
+        * reuse it the next time */
+
+       G_Conf.setPath(G_Conf.patchPath, fpath);
+
+       gLog("[glue] patch %s loaded\n", fname);
+
+#ifdef WITH_VST
+       if (resPlugins != 1)
+               gdAlert("Some VST plugins were not loaded successfully.");
+#endif
+
+       return res;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_savePatch(const char *fullpath, const char *name, bool isProject)
+{
+       if (G_Patch.write(fullpath, name, isProject) == 1) {
+               strcpy(G_Patch.name, name);
+               G_Patch.name[strlen(name)] = '\0';
+               gu_update_win_label(name);
+               gLog("[glue] patch saved as %s\n", fullpath);
+               return 1;
+       }
+       else
+               return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_deleteChannel(Channel *ch)
+{
+       int index = ch->index;
+       recorder::clearChan(index);
+       Fl::lock();
+       mainWin->keyboard->deleteChannel(ch->guiChannel);
+       Fl::unlock();
+       G_Mixer.deleteChannel(ch);
+       gu_closeAllSubwindows();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_freeChannel(Channel *ch)
+{
+       mainWin->keyboard->freeChannel(ch->guiChannel);
+       recorder::clearChan(ch->index);
+       ch->empty();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBpm(const char *v1, const char *v2)
+{
+       char  buf[6];
+       float value = atof(v1) + (atof(v2)/10);
+       if (value < 20.0f)      {
+               value = 20.0f;
+               sprintf(buf, "20.0");
+       }
+       else
+               sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2);
+
+       /* a value such as atof("120.1") will never be 120.1 but 120.0999999,
+        * because of the rounding error. So we pass the real "wrong" value to
+        * G_Mixer and we show the nice looking (but fake) one to the GUI. */
+
+       float old_bpm = G_Mixer.bpm;
+       G_Mixer.bpm = value;
+       G_Mixer.updateFrameBars();
+
+       /* inform recorder and actionEditor of the change */
+
+       recorder::updateBpm(old_bpm, value, G_Mixer.quanto);
+       gu_refreshActionEditor();
+
+       mainWin->timing->setBpm(buf);
+       gLog("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBeats(int beats, int bars, bool expand)
+{
+       /* temp vars to store old data (they are necessary) */
+
+       int      oldvalue = G_Mixer.beats;
+       unsigned oldfpb         = G_Mixer.totalFrames;
+
+       if (beats > MAX_BEATS)
+               G_Mixer.beats = MAX_BEATS;
+       else if (beats < 1)
+               G_Mixer.beats = 1;
+       else
+               G_Mixer.beats = beats;
+
+       /* update bars - bars cannot be greate than beats and must be a sub
+        * multiple of beats. If not, approximation to the nearest (and greater)
+        * value available. */
+
+       if (bars > G_Mixer.beats)
+               G_Mixer.bars = G_Mixer.beats;
+       else if (bars <= 0)
+               G_Mixer.bars = 1;
+       else if (beats % bars != 0) {
+               G_Mixer.bars = bars + (beats % bars);
+               if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it)
+                       G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars);
+       }
+       else
+               G_Mixer.bars = bars;
+
+       G_Mixer.updateFrameBars();
+
+       /* update recorded actions */
+
+       if (expand) {
+               if (G_Mixer.beats > oldvalue)
+                       recorder::expand(oldfpb, G_Mixer.totalFrames);
+               //else if (G_Mixer.beats < oldvalue)
+               //      recorder::shrink(G_Mixer.totalFrames);
+       }
+
+       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
+       gu_refreshActionEditor();  // in case the action editor is open
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopSeq(bool gui)
+{
+       G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startSeq(bool gui)
+{
+       G_Mixer.running = true;
+
+       if (gui) {
+#ifdef __linux__
+               kernelAudio::jackStart();
+#endif
+       }
+
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
+               kernelMidi::send(MIDI_START, -1, -1);
+               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
+       }
+
+       if (gui) Fl::lock();
+       mainWin->controller->updatePlay(1);
+       if (gui) Fl::unlock();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopSeq(bool gui) {
+
+       mh_stopSequencer();
+
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
+               kernelMidi::send(MIDI_STOP, -1, -1);
+
+#ifdef __linux__
+       if (gui)
+               kernelAudio::jackStop();
+#endif
+
+       /* what to do if we stop the sequencer and some action recs are active?
+        * Deactivate the button and delete any 'rec on' status */
+
+       if (recorder::active) {
+               recorder::active = false;
+               if (gui) Fl::lock();
+               mainWin->controller->updateRecAction(0);
+               if (gui) Fl::unlock();
+       }
+
+       /* if input recs are active (who knows why) we must deactivate them.
+        * One might stop the sequencer while an input rec is running. */
+
+       if (G_Mixer.chanInput != NULL) {
+               mh_stopInputRec();
+               if (gui) Fl::lock();
+               mainWin->controller->updateRecInput(0);
+               if (gui) Fl::unlock();
+       }
+
+       if (gui) Fl::lock();
+       mainWin->controller->updatePlay(0);
+       if (gui) Fl::unlock();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_rewindSeq() {
+       mh_rewindSequencer();
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
+               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopActionRec() {
+       recorder::active ? glue_stopActionRec() : glue_startActionRec();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startActionRec() {
+       if (G_audio_status == false)
+               return;
+       if (!G_Mixer.running)
+               glue_startSeq();                // start the sequencer for convenience
+       recorder::active = true;
+
+       Fl::lock();
+       mainWin->controller->updateRecAction(1);
+       Fl::unlock();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopActionRec() {
+
+       /* stop the recorder and sort new actions */
+
+       recorder::active = false;
+       recorder::sortActions();
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
+                       SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
+                       if (ch->hasActions)
+                               ch->readActions = true;
+                       else
+                               ch->readActions = false;
+                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel);
+               }
+
+       Fl::lock();
+       mainWin->controller->updateRecAction(0);
+       Fl::unlock();
+
+       /* in case acton editor is on, refresh it */
+
+       gu_refreshActionEditor();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopReadingRecs(SampleChannel *ch, bool gui) {
+       if (ch->readActions)
+               glue_stopReadingRecs(ch, gui);
+       else
+               glue_startReadingRecs(ch, gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startReadingRecs(SampleChannel *ch, bool gui) {
+       if (G_Conf.treatRecsAsLoops)
+               ch->recStatus = REC_WAITING;
+       else
+               ch->setReadActions(true);
+       if (!gui) {
+               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
+               if (gch->readActions) { // if button exists
+                       Fl::lock();
+                       gch->readActions->value(1);
+                       Fl::unlock();
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopReadingRecs(SampleChannel *ch, bool gui) {
+
+       /* if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put
+        * the channel in REC_ENDING status */
+
+       if (G_Conf.treatRecsAsLoops)
+               ch->recStatus = REC_ENDING;
+       else
+               ch->setReadActions(false);
+       if (!gui) {
+               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
+               if (gch->readActions) {  // if button exists
+                       Fl::lock();
+                       gch->readActions->value(0);
+                       Fl::unlock();
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_quantize(int val) {
+       G_Mixer.quantize = val;
+       G_Mixer.updateQuanto();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setChanVol(Channel *ch, float v, bool gui) {
+
+       ch->volume = v;
+
+       /* also update wave editor if it's shown */
+
+       gdEditor *editor = (gdEditor*) gu_getSubwindow(mainWin, WID_SAMPLE_EDITOR);
+       if (editor) {
+               glue_setVolEditor(editor, (SampleChannel*) ch, v, false);
+               Fl::lock();
+               editor->volume->value(v);
+               Fl::unlock();
+       }
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->vol->value(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setOutVol(float v, bool gui) {
+       G_Mixer.outVol = v;
+       if (!gui) {
+               Fl::lock();
+               mainWin->inOut->setOutVol(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setInVol(float v, bool gui)
+{
+       G_Mixer.inVol = v;
+       if (!gui) {
+               Fl::lock();
+               mainWin->inOut->setInVol(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_clearAllSamples()
+{
+       G_Mixer.running = false;
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               G_Mixer.channels.at(i)->empty();
+               G_Mixer.channels.at(i)->guiChannel->reset();
+       }
+       recorder::init();
+       return;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_clearAllRecs()
+{
+       recorder::init();
+       gu_updateControls();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_resetToInitState(bool resetGui, bool createColumns)
+{
+       G_Mixer.ready = false;
+
+       mh_clear();
+       mainWin->keyboard->clear();
+       if (createColumns)
+               mainWin->keyboard->init();
+       recorder::init();
+       G_Patch.setDefault();
+       G_Mixer.init();
+#ifdef WITH_VST
+       G_PluginHost.freeAllStacks();
+#endif
+
+       if (resetGui)
+               gu_updateControls();
+
+       G_Mixer.ready = true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopMetronome(bool gui)
+{
+       G_Mixer.metronome = !G_Mixer.metronome;
+       if (!gui) {
+               Fl::lock();
+               mainWin->controller->updateMetronome(G_Mixer.metronome);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, bool recalc, bool check)
+{
+       if (check) {
+               if (e > ch->wave->size)
+                       e = ch->wave->size;
+               if (b < 0)
+                       b = 0;
+               if (b > ch->wave->size)
+                       b = ch->wave->size-2;
+               if (b >= ch->end)
+                       b = ch->begin;
+               if (e <= ch->begin)
+                       e = ch->end;
+       }
+
+       /* continue only if new values != old values */
+
+       if (b == ch->begin && e == ch->end)
+               return;
+
+       /* print mono values */
+
+       char tmp[16];
+       sprintf(tmp, "%d", b/2);
+       win->chanStart->value(tmp);
+
+       tmp[0] = '\0';
+       sprintf(tmp, "%d", e/2);
+       win->chanEnd->value(tmp);
+
+       ch->setBegin(b);
+       ch->setEnd(e);
+
+       /* recalc is not needed when the user drags the bars directly over the waveform */
+
+       if (recalc) {
+               win->waveTools->waveform->recalcPoints();       // importante, altrimenti non si vedono
+               win->waveTools->waveform->redraw();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric)
+{
+       if (numeric) {
+               if (val > 20.0f)
+                       val = 20.0f;
+               else if (val < 0.0f)
+                       val = 0.0f;
+
+         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
+
+               ch->boost = linear;
+
+               char buf[10];
+               sprintf(buf, "%.2f", val);
+               win->boostNum->value(buf);
+               win->boostNum->redraw();
+
+               win->boost->value(linear);
+               win->boost->redraw();       /// inutile
+       }
+       else {
+               ch->boost = val;
+               char buf[10];
+               sprintf(buf, "%.2f", 20*log10(val));
+               win->boostNum->value(buf);
+               win->boostNum->redraw();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
+{
+       if (numeric) {
+               if (val > 0.0f)
+                       val = 0.0f;
+               else if (val < -60.0f)
+                       val = -INFINITY;
+
+         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
+
+               ch->volume = linear;
+
+               win->volume->value(linear);
+               win->volume->redraw();
+
+               char buf[10];
+               if (val > -INFINITY)
+                       sprintf(buf, "%.2f", val);
+               else
+                       sprintf(buf, "-inf");
+               win->volumeNum->value(buf);
+               win->volumeNum->redraw();
+
+               ch->guiChannel->vol->value(linear);
+               ch->guiChannel->vol->redraw();
+       }
+       else {
+               ch->volume = val;
+
+               float dbVal = 20 * log10(val);
+               char buf[10];
+               if (dbVal > -INFINITY)
+                       sprintf(buf, "%.2f", dbVal);
+               else
+                       sprintf(buf, "-inf");
+
+               win->volumeNum->value(buf);
+               win->volumeNum->redraw();
+
+               ch->guiChannel->vol->value(val);
+               ch->guiChannel->vol->redraw();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setMute(Channel *ch, bool gui)
+{
+       if (recorder::active && recorder::canRec(ch)) {
+               if (!ch->mute)
+                       recorder::startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame);
+               else
+                recorder::stopOverdub(G_Mixer.actualFrame);
+       }
+
+       ch->mute ? ch->unsetMute(false) : ch->setMute(false);
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->mute->value(ch->mute);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setSoloOn(Channel *ch, bool gui)
+{
+       /* if there's no solo session, store mute configuration of all chans
+        * and start the session */
+
+       if (!__soloSession__) {
+               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+                       Channel *och = G_Mixer.channels.at(i);
+                       och->mute_s  = och->mute;
+               }
+               __soloSession__ = true;
+       }
+
+       ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
+
+       /* mute all other channels and unmute this (if muted) */
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+               Channel *och = G_Mixer.channels.at(i);
+               if (!och->solo && !och->mute) {
+                       och->setMute(false);
+                       Fl::lock();
+                       och->guiChannel->mute->value(true);
+                       Fl::unlock();
+               }
+       }
+
+       if (ch->mute) {
+               ch->unsetMute(false);
+               Fl::lock();
+               ch->guiChannel->mute->value(false);
+               Fl::unlock();
+       }
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->solo->value(1);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setSoloOff(Channel *ch, bool gui)
+{
+       /* if this is uniqueSolo, stop solo session and restore mute status,
+        * else mute this */
+
+       if (mh_uniqueSolo(ch)) {
+               __soloSession__ = false;
+               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+                       Channel *och = G_Mixer.channels.at(i);
+                       if (och->mute_s) {
+                               och->setMute(false);
+                               Fl::lock();
+                               och->guiChannel->mute->value(true);
+                               Fl::unlock();
+                       }
+                       else {
+                               och->unsetMute(false);
+                               Fl::lock();
+                               och->guiChannel->mute->value(false);
+                               Fl::unlock();
+                       }
+                       och->mute_s = false;
+               }
+       }
+       else {
+               ch->setMute(false);
+               Fl::lock();
+               ch->guiChannel->mute->value(true);
+               Fl::unlock();
+       }
+
+       ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->solo->value(0);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val)
+{
+       if (val < 1.0f) {
+               ch->panLeft = 1.0f;
+               ch->panRight= 0.0f + val;
+
+               char buf[8];
+               sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100));
+               win->panNum->value(buf);
+       }
+       else if (val == 1.0f) {
+               ch->panLeft = 1.0f;
+               ch->panRight= 1.0f;
+         win->panNum->value("C");
+       }
+       else {
+               ch->panLeft = 2.0f - val;
+               ch->panRight= 1.0f;
+
+               char buf[8];
+               sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100));
+               win->panNum->value(buf);
+       }
+       win->panNum->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopInputRec(bool gui, bool alert)
+{
+       if (G_Mixer.chanInput == NULL) {
+               if (!glue_startInputRec(gui)) {
+                       if (alert) gdAlert("No channels available for recording.");
+                       else       gLog("[glue] no channels available for recording\n");
+               }
+       }
+       else
+               glue_stopInputRec(gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_startInputRec(bool gui)
+{
+       if (G_audio_status == false)
+               return -1;
+
+       SampleChannel *ch = mh_startInputRec();
+       if (ch == NULL) {                  // no chans available
+               Fl::lock();
+               mainWin->controller->updateRecInput(0);
+               Fl::unlock();
+               return 0;
+       }
+
+       if (!G_Mixer.running) {
+               glue_startSeq();
+               Fl::lock();
+               mainWin->controller->updatePlay(1);
+               Fl::unlock();
+       }
+
+       glue_setChanVol(ch, 1.0f, false); // false = not from gui click
+
+       ch->guiChannel->mainButton->label(ch->wave->name.c_str());
+
+       if (!gui) {
+               Fl::lock();
+               mainWin->controller->updateRecInput(1);
+               Fl::unlock();
+       }
+
+       return 1;
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_stopInputRec(bool gui)
+{
+       SampleChannel *ch = mh_stopInputRec();
+
+       if (ch->mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT))
+               ch->start(0, true);  // on frame 0: user-generated event
+
+       if (!gui) {
+               Fl::lock();
+               mainWin->controller->updateRecInput(0);
+               Fl::unlock();
+       }
+
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_saveProject(const char *folderPath, const char *projName)
+{
+       if (gIsProject(folderPath)) {
+               gLog("[glue] the project folder already exists\n");
+               // don't exit
+       }
+       else if (!gMkdir(folderPath)) {
+               gLog("[glue] unable to make project directory!\n");
+               return 0;
+       }
+
+       /* copy all samples inside the folder. Takes and logical ones are saved
+        * via glue_saveSample() */
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+
+               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
+
+                       SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
+
+                       if (ch->wave == NULL)
+                               continue;
+
+                       /* update the new samplePath: everything now comes from the
+                        * project folder (folderPath) */
+
+                       char samplePath[PATH_MAX];
+                       sprintf(samplePath, "%s%s%s.%s", folderPath, gGetSlash().c_str(), ch->wave->basename().c_str(), ch->wave->extension().c_str());
+
+                       /* remove any existing file */
+
+                       if (gFileExists(samplePath))
+                               remove(samplePath);
+                       if (ch->save(samplePath))
+                               ch->wave->pathfile = samplePath;
+               }
+       }
+
+       char gptcPath[PATH_MAX];
+       sprintf(gptcPath, "%s%s%s.gptc", folderPath, gGetSlash().c_str(), gStripExt(projName).c_str());
+       glue_savePatch(gptcPath, projName, true); // true == it's a project
+
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyPress(Channel *ch, bool ctrl, bool shift)
+{
+       if (ch->type == CHANNEL_SAMPLE)
+               glue_keyPress((SampleChannel*)ch, ctrl, shift);
+       else
+               glue_keyPress((MidiChannel*)ch, ctrl, shift);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyRelease(Channel *ch, bool ctrl, bool shift)
+{
+       if (ch->type == CHANNEL_SAMPLE)
+               glue_keyRelease((SampleChannel*)ch, ctrl, shift);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift)
+{
+       if (ctrl)
+               glue_setMute(ch);
+       else
+       if (shift)
+               ch->kill(0);        // on frame 0: user-generated event
+       else
+               ch->start(0, true); // on frame 0: user-generated event
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift)
+{
+       /* case CTRL */
+
+       if (ctrl)
+               glue_setMute(ch);
+
+       /* case SHIFT
+        *
+        * action recording on:
+        *              if seq is playing, rec a killchan
+        * action recording off:
+        *              if chan has recorded events:
+        *              |        if seq is playing OR channel 'c' is stopped, de/activate recs
+        *              |        else kill chan
+        *              else kill chan */
+
+       else
+       if (shift) {
+               if (recorder::active) {
+                       if (G_Mixer.running) {
+                               ch->kill(0); // on frame 0: user-generated event
+                               if (recorder::canRec(ch) && !(ch->mode & LOOP_ANY))   // don't record killChan actions for LOOP channels
+                                       recorder::rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame);
+                       }
+               }
+               else {
+                       if (ch->hasActions) {
+                               if (G_Mixer.running || ch->status == STATUS_OFF)
+                                       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
+                               else
+                                       ch->kill(0);  // on frame 0: user-generated event
+                       }
+                       else
+                               ch->kill(0);    // on frame 0: user-generated event
+               }
+       }
+
+       /* case no modifier */
+
+       else {
+
+               /* record now if the quantizer is off, otherwise let mixer to handle it
+                * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are
+                * meaningless for loop modes */
+
+               if (G_Mixer.quantize == 0 &&
+                   recorder::canRec(ch)  &&
+             !(ch->mode & LOOP_ANY))
+               {
+                       if (ch->mode == SINGLE_PRESS)
+                               recorder::startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame);
+                       else
+                               recorder::rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame);
+               }
+
+               ch->start(0, true); // on frame 0: user-generated event
+       }
+
+       /* the GUI update is done by gui_refresh() */
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift)
+{
+       if (!ctrl && !shift) {
+               ch->stop();
+
+               /* record a key release only if channel is single_press. For any
+                * other mode the KEY REL is meaningless. */
+
+               if (ch->mode == SINGLE_PRESS && recorder::canRec(ch))
+                       recorder::stopOverdub(G_Mixer.actualFrame);
+       }
+
+       /* the GUI update is done by gui_refresh() */
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setPitch(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
+{
+       if (numeric) {
+               if (val <= 0.0f)
+                       val = 0.1000f;
+               if (val > 4.0f)
+                       val = 4.0000f;
+               if (win)
+                       win->pitch->value(val);
+       }
+
+       ch->setPitch(val);
+
+       if (win) {
+               char buf[16];
+               sprintf(buf, "%.4f", val);
+               Fl::lock();
+               win->pitchNum->value(buf);
+               win->pitchNum->redraw();
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* never expand or shrink recordings (last param of setBeats = false):
+ * this is live manipulation */
+
+void glue_beatsMultiply()
+{
+       glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false);
+}
+
+void glue_beatsDivide()
+{
+       glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false);
+}
diff --git a/src/glue/glue.h b/src/glue/glue.h
new file mode 100644 (file)
index 0000000..d018a6c
--- /dev/null
@@ -0,0 +1,169 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GLUE_H
+#define GLUE_H
+
+/* addChannel
+ * add an empty new channel to the stack. Returns the new channel. */
+
+class Channel *glue_addChannel(int column, int type);
+
+/* loadChannel
+ * fill an existing channel with a wave. */
+
+int glue_loadChannel(class SampleChannel *ch, const char *fname);
+
+void glue_deleteChannel(class Channel *ch);
+
+void glue_freeChannel(class Channel *ch);
+
+/** FIXME - nobody will call these via MIDI/keyb/mouse! */
+int glue_loadPatch(const char *fname, const char *fpath, class gProgress *status, bool isProject);
+int glue_savePatch(const char *fullpath, const char *name, bool isProject);
+
+/* keyPress / keyRelease
+ * handle the key pressure, either via mouse/keyboard or MIDI. If gui
+ * is true it means that the event comes from the main window (mouse,
+ * keyb or MIDI), otherwise the event comes from the action recorder. */
+
+void glue_keyPress  (class Channel       *ch, bool ctrl=0, bool shift=0);
+void glue_keyPress  (class SampleChannel *ch, bool ctrl=0, bool shift=0);
+void glue_keyPress  (class MidiChannel   *ch, bool ctrl=0, bool shift=0);
+void glue_keyRelease(class Channel       *ch, bool ctrl=0, bool shift=0);
+void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0);
+
+void glue_setBpm(const char *v1, const char *v2);
+void glue_setBeats(int beats, int bars, bool expand);
+
+/* start, stop, rewind sequencer
+ * if gui == true the signal comes from an internal interaction on the
+ * GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_startStopSeq(bool gui=true);
+void glue_startSeq    (bool gui=true);
+void glue_stopSeq     (bool gui=true);
+void glue_rewindSeq   ();
+
+/* start/stopActionRec
+ * handle the action recording. */
+
+void glue_startStopActionRec();
+void glue_startActionRec();
+void glue_stopActionRec();
+
+/* start/stopInputRec
+ * handle the input recording (take). If gui == true the signal comes
+ * from an internal interaction on the GUI, otherwise it's a
+ * MIDI/Jack/external signal. Alert displays or not the popup message
+ * if there are no available channels. */
+
+void glue_startStopInputRec(bool gui=true, bool alert=true);
+int  glue_startInputRec    (bool gui=true);
+int  glue_stopInputRec     (bool gui=true);
+
+/* start/stopReadingRecs
+ * handle the 'R' button. If gui == true the signal comes from an
+ * internal interaction on the GUI, otherwise it's a MIDI/Jack/external
+ * signal. */
+
+void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true);
+void glue_startReadingRecs    (class SampleChannel *ch, bool gui=true);
+void glue_stopReadingRecs     (class SampleChannel *ch, bool gui=true);
+
+void glue_quantize(int val);
+
+void glue_setChanVol(class Channel *ch, float v, bool gui=true);
+void glue_setOutVol (float v, bool gui=true);
+void glue_setInVol  (float v, bool gui=true);
+
+void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val);
+
+void glue_clearAllSamples();
+void glue_clearAllRecs();
+
+/* resetToInitState
+ * reset Giada to init state. If resetGui also refresh all widgets. If
+ * createColumns also build initial empty columns. */
+
+void glue_resetToInitState(bool resetGui=true, bool createColumns=true);
+
+void glue_startStopMetronome(bool gui=true);
+
+/* setBeginEndChannel
+ * sets start/end points in the sample editor.
+ * Recalc=false: don't recalc internal position
+ * check=true: check the points' consistency */
+
+/** FIXME - nobody will call this via MIDI/keyb/mouse! */
+void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, int b, int e,
+                                                                                                                bool recalc=false, bool check=true);
+
+/** FIXME - nobody will call this via MIDI/keyb/mouse! */
+void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
+
+void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
+
+/* setVolEditor
+ * handles the volume inside the SAMPLE EDITOR (not the main gui). The
+ * numeric flag tells if we want to handle the dial or the numeric input
+ * field. */
+
+ /** FIXME - nobody will call this via MIDI/keyb/mouse! */
+void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
+
+/* mute
+ * set mute on or off. If gui == true the signal comes from an internal
+ * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_setMute(class Channel *ch, bool gui=true);
+
+/* solo on/off
+ * set solo on and off. If gui == true the signal comes from an internal
+ * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_setSoloOn (class Channel *ch, bool gui=true);
+void glue_setSoloOff(class Channel *ch, bool gui=true);
+
+/** FIXME - nobody will call this via MIDI/keyb/mouse! */
+int glue_saveProject(const char *folderPath, const char *projName);
+
+
+/* beatsDivide/Multiply
+ * shrinks or enlarges the number of beats by 2. */
+
+void glue_beatsMultiply();
+void glue_beatsDivide();
+
+#endif
diff --git a/src/graphics.cpp b/src/graphics.cpp
deleted file mode 100644 (file)
index 82ca2bc..0000000
+++ /dev/null
@@ -1,1631 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * graphics
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#include "graphics.h"
-
-const char *giada_logo_xpm[] = {
-"300 82 8 1",
-"      c #181917",
-".     c #333432",
-"+     c #484A47",
-"@     c #5F615E",
-"#     c #767875",
-"$     c #8D8F8C",
-"%     c #A5A7A4",
-"&     c #C5C7C4",
-"                                                                                                                                                          .#%%&$                                                                                                                                            ",
-"                                                                                                                                                      ..#%&&&&&#                                                                                                                                            ",
-"                                                                                                                                                 +@#$%&&&&&&&&&@                                                                                                                                            ",
-"                                                              ..                                                                                +&&&&&&&&&&&&&&.                                                                                                                                            ",
-"                                                            +$%%#+                                                                              +%&&&&&&&&&&&&&.                                                                                                                                            ",
-"                                                           #&&&&&%+                                                                             .+@@$&&&&&&&&&%.                                                                                                                                            ",
-"                                                          #&&&&&&&$                                                                                  +&&&&&&&&#                                                                                                                                             ",
-"                                                         .&&&&&&&&%.                                                                                  #&&&&&&&@                                                                                                                                             ",
-"                                                         @&&&&&&&&$                                                                                   +&&&&&&&+                                                                                                                                             ",
-"                                                         $&&&&&&&&#                                                                                   .&&&&&&&.                                                                                                                                             ",
-"                                                         #&&&&&&&&.                                                                                   +&&&&&&%.                                                                                                                                             ",
-"                                                         .&&&&&&&@                                                                                    @&&&&&&$.                                                                                                                                             ",
-"                                                          @&&&&&@                                                                                     $&&&&&&#                                                                                                                                              ",
-"                                                           .##@.                                                                                      %&&&&&&@                                                                                                                                              ",
-"                                                                                                                                                      &&&&&&&+                                                                                                                                              ",
-"                                                                                                                                                     .&&&&&&%.                                                                                                                                              ",
-"                                                                                                                                                     @&&&&&&$.                                                                                                                                              ",
-"                     .+@@###@+.        ......               ...                      ++@@###@@.       .......                      .+@@###@@+.       #&&&&&&#                       .+@@###@@+        .......                                                                                               ",
-"                  .@$%%&&&&&&&%$+     +%%%%%%.         .+@#$%%$.                  .@$%&&&&&&&&%$@.    $%%%%%%+                  .@#%%&&&&&&&&%$@     %&&&&&&@                    .@$%%&&&&&&&%$#.    @%%%%%%@                                                                                               ",
-"                 #%&&&&&&&&&&&&&&$.   #&&&&&&    +@#$$%%%&&&&&%.                .$%&&&&&&&&&&&&&&%@  .&&&&&&&+                 #%&&&&&&&&&&&&&&&$+   &&&&&&&@                   #%&&&&&&&&&&&&&&%#.  %&&&&&&@                                                                                               ",
-"               +%&&&&&&&&&&&&&&&&&%@ .&&&&&&%   .%&&&&&&&&&&&&$                #%&&&&&&&&&&&&&&&&&&$ +&&&&&&%.               @%&&&&&&&&&&&&&&&&&&&# .&&&&&&%+                 @%&&&&&&&&&&&&&&&&&&%. &&&&&&&+                                                                                               ",
-"              #&&&&&&&&&#+....@$&&&&@@&&&&&&$   .&&&&&&&&&&&&&#              +%&&&&&&&&%#+....+#%&&&$#&&&&&&$.             .$&&&&&&&&&$+.....@%&&&&$@&&&&&&%.               .$&&&&&&&&&#@.....#%&&&%+&&&&&&%.                                                                                               ",
-"             $&&&&&&&&@         .%&&&&&&&&&&@    .@$&&&&&&&&&&@             +%&&&&&&&%@         .#&&&&&&&&&&$             .%&&&&&&&&@          .$&&&&&&&&&&$               .%&&&&&&&&#.         @&&&&&&&&&&%.                                                                                               ",
-"            $&&&&&&&%.            @&&&&&&&&&+       .%&&&&&&&%+            @&&&&&&&&#             +%&&&&&&&&#            +%&&&&&&&$.             @&&&&&&&&&#              .%&&&&&&&$.            .%&&&&&&&&$                                                                                                ",
-"           %&&&&&&&#               @&&&&&&&&.        +%&&&&&&%.           @&&&&&&&&#               .%&&&&&&&@           +%&&&&&&&#                @&&&&&&&&@             +%&&&&&&&#                %&&&&&&&@                                                                                                ",
-"          $&&&&&&&$                 #&&&&&&%.         %&&&&&&%           +&&&&&&&&@                 +&&&&&&%+          .%&&&&&&&#                  @&&&&&&&+            .%&&&&&&&#                  &&&&&&&+                                                                                                ",
-"         @&&&&&&&$.                 #&&&&&&$          %&&&&&&$          .%&&&&&&&@                  @&&&&&&%.         .$&&&&&&&$                   +&&&&&&%+            $&&&&&&&$                  .&&&&&&&+                                                                                                ",
-"        +&&&&&&&%+                  %&&&&&&#          %&&&&&&#          $&&&&&&&$                   $&&&&&&%          @&&&&&&&%                    #&&&&&&%.           #&&&&&&&%.                  @&&&&&&%.                                                                                                ",
-"        %&&&&&&&#                   &&&&&&&+         .%&&&&&&@         @&&&&&&&$                    %&&&&&&$         +&&&&&&&&+                    $&&&&&&$           +&&&&&&&%.                   $&&&&&&$.                                                                                                ",
-"       @&&&&&&&%.                  .&&&&&&&.         +%&&&&&%.        .&&&&&&&&.                   .%&&&&&&#         $&&&&&&&#                     %&&&&&&#          .$&&&&&&&@                    %&&&&&&#                                                                                                 ",
-"      .%&&&&&&&@                   @&&&&&&&.         @&&&&&&%         @&&&&&&&#                    @&&&&&&&+        +&&&&&&&&.                    +&&&&&&&@          +&&&&&&&%                    .&&&&&&&@                                                                                                 ",
-"      @&&&&&&&%                    $&&&&&&%.         #&&&&&&%         &&&&&&&&.                    #&&&&&&%.        %&&&&&&&#                     @&&&&&&%+         .$&&&&&&&@                    +&&&&&&&+                                                                                                 ",
-"     .$&&&&&&&#                    %&&&&&&#          $&&&&&&#        #&&&&&&&#                     $&&&&&&%        +&&&&&&&&.                     $&&&&&&%.         +&&&&&&&%                     #&&&&&&%+                                                                                                 ",
-"     +%&&&&&&&+                   .&&&&&&&@         .%&&&&&&@        %&&&&&&&+                    .%&&&&&&$        $&&&&&&&$                      %&&&&&&%          #&&&&&&&#                     %&&&&&&%.                                                                                                 ",
-"     @&&&&&&&%                    +&&&&&&&+         +%&&&&&&+       .&&&&&&&%.                    +&&&&&&&#        &&&&&&&&+                     +%&&&&&&$         .%&&&&&&&.                     &&&&&&&$                                                                                                  ",
-"     $&&&&&&&@                    #&&&&&&&.         @&&&&&&&.       #&&&&&&&#                     #&&&&&&&@       +&&&&&&&%.                     @&&&&&&&#         .&&&&&&&%                     +&&&&&&&#                                                                                                  ",
-"    .%&&&&&&&.                    %&&&&&&%.         #&&&&&&%        %&&&&&&&+                     $&&&&&&&+       #&&&&&&&$.                     $&&&&&&&+         @&&&&&&&@                     #&&&&&&&@                                                                                                  ",
-"    +&&&&&&&&                     &&&&&&&$.         #&&&&&&$        &&&&&&&%.                    .%&&&&&&&        %&&&&&&&#                     .%&&&&&&%.         $&&&&&&&+                     $&&&&&&%+                                                                                                  ",
-"    +&&&&&&&$                    +&&&&&&&#         .$&&&&&&#       .&&&&&&&$.                    +&&&&&&&%        %&&&&&&&+                     +%&&&&&&%          %&&&&&&&.                    .%&&&&&&%.                                                                                                  ",
-"    @&&&&&&&@                    $&&&&&&&@         .%&&&&&&+       +&&&&&&&#                     #&&&&&&&$        &&&&&&&&+                     #&&&&&&&%          &&&&&&&%                     @&&&&&&&$                                                                                                   ",
-"    @&&&&&&&+                    &&&&&&&&+         +%&&&&&&.       @&&&&&&&@                    .%&&&&&&&@       .&&&&&&&%.                    .%&&&&&&&#          &&&&&&&#                     $&&&&&&&$                                                                                                   ",
-"    #&&&&&&&.                   @&&&&&&&%.         @&&&&&&&        @&&&&&&&@                    @&&&&&&&&+       .&&&&&&&%.                    @&&&&&&&&@         .&&&&&&&#                    +%&&&&&&&#                                                                                                   ",
-"    #&&&&&&&.                   %&&&&&&&$.         #&&&&&&%        #&&&&&&&+                   .$&&&&&&&&.       .&&&&&&&$.                   .$&&&&&&&&.         .&&&&&&&@                    $&&&&&&&&@                                                                                                   ",
-"    #&&&&&&&                   #&&&&&&&&$          $&&&&&&#        @&&&&&&&+                   @&&&&&&&&&        .&&&&&&&$.                   @&&&&&&&&&          .&&&&&&&+                   +%&&&&&&&%+                                                                                                   ",
-"    @&&&&&&&                  .%&&&&&&&&#         .%&&&&&&@        @&&&&&&%+                  .%&&&&&&&&%         &&&&&&&$.                  .%&&&&&&&&%           &&&&&&&+                   $&&&&&&&&%.                                                                                                   ",
-"    @&&&&&&&.                 $&&&&&&&&&@         +%&&&&&&.        +&&&&&&&@                  @&&&&&&&&&$         &&&&&&&%.                  #&&&&&&&&&$           &&&&&&&@                  +&&&&&&&&&%                                                                                                    ",
-"    +&&&&&&&+                @&&&&&&&&&%+         +&&&&&&&          &&&&&&&@                 +&&&&&&&&&&#         $&&&&&&%+                 @&&&&&&&&&&#           $&&&&&&#                 .%&&&&&&&&&%                                                                                                    ",
-"    .%&&&&&&@               +%&&$&&&&&&%.         +&&&&&&&          %&&&&&&#                .&&&&&&&&&&&@         @&&&&&&&+                +&&&$%&&&&&&@           @&&&&&&$                .$&&&&&&&&&&$                                                                                                    ",
-"     #&&&&&&$              .$&&##&&&&&&$          @&&&&&&&          @&&&&&&%.              .%&&%@%&&&&&&@         .&&&&&&&#               .&&&$+%&&&&&&.           .&&&&&&&.              .#&&%@%&&&&&&$                                                                                                    ",
-"     +&&&&&&&.            .%&&% $&&&&&&#          +&&&&&&&.        +.&&&&&&&@             .%&&%+.%&&&&&&$        @+$&&&&&&&+             +&&&% +&&&&&&&+        .+  $&&&&&&$             .$&&&@ %&&&&&&%        .#                                                                                          ",
-"      $&&&&&&$           +%&&&+ %&&&&&&@          +&&&&&&&@       #&$#&&&&&&%+           @&&&&@ .$&&&&&&&+      #&&@&&&&&&&$.          .#&&&%. +%&&&&&&#       .$&$ +&&&&&&&+           +%&&&#  $&&&&&&&#      +&&$                                                                                         ",
-"      +%&&&&&&#.       +#&&&%@ .%&&&&&&+          .%&&&&&&&+    .$&&%.%&&&&&&%+        +#&&&&@   #&&&&&&&%@..+@$&&&+@&&&&&&&%+       .@%&&&%+  .%&&&&&&&+     +%&&$. #&&&&&&%@        +#&&&&#   @&&&&&&&&@...+#&&&#                                                                                         ",
-"       @&&&&&&&$@+..++#%&&&%+  +&&&&&&%.           $&&&&&&&%#@@#%&&%. .%&&&&&&%@+...+@$&&&&%+    +%&&&&&&&&%$%&&&&+  $&&&&&&&&$#@+@@#%&&&&$.    #&&&&&&&&#@+@$&&&$.  .$&&&&&&&#+...++#%&&&&@    .%&&&&&&&&%$%&&&&#                                                                                          ",
-"        @&&&&&&&&%%%%&&&&&$.   @&&&&&&%            +%&&&&&&&&&&&&&$.   +%&&&&&&&&%$%%&&&&&$.      #&&&&&&&&&&&&&%+   .$&&&&&&&&&&&&&&&&&&#      .%&&&&&&&&&&&&&&#     .$&&&&&&&&%$%%&&&&&%+      @&&&&&&&&&&&&&%@                                                                                           ",
-"         @%&&&&&&&&&&&&&%@.    #&&&&&&$             #&&&&&&&&&&&%@.     .$&&&&&&&&&&&&&&%@.       .%&&&&&&&&&&&#.      @&&&&&&&&&&&&&&&$+        +&&&&&&&&&&&&%+       .#&&&&&&&&&&&&&&&#.        $&&&&&&&&&&&$+                                                                                            ",
-"          .#%&&&&&&&&&%+.      %&&&&&&#              +%&&&&&&&%#.         +$&&&&&&&&&&%@.          .$&&&&&&&&#+         .#&&&&&&&&&&%#.           .$&&&&&&&&%@.          +$&&&&&&&&&&%@.          .@&&&&&&&&$+.                                                                                             ",
-"            .+#$%%$#+..       .%&&&&&&+               .@#$%$#+.             .@#$%%$#@+               +@$%$#+.             .+#$%%$#@+.               +@$%$$@.               .+#$%%$#@+.              .@$%$#@.                                                                                                ",
-"                              +&&&&&&%.                                                                                                                                                                                                                                                                     ",
-"                              #&&&&&&%                                                                                                                                                                                                                                                                      ",
-"                             .%&&&&&&@                                                                                                                                                                                                                                                                      ",
-"                             @&&&&&&%.                                                                                                                                                                                                                                                                      ",
-"                             $&&&&&&$                                                                                                                                                                                                                                                                       ",
-"                            @&&&&&&&+                                                                                                                                                                                                                                                                       ",
-"  @#$#+                    .$&&&&&&$                                                                                                                                                                                                                                                                        ",
-" $&&&&&#                   #&&&&&&%                                                                                                                                                                                                                                                                         ",
-"#&&&&&&&@                 @&&&&&&&+                                                                                                                                                                                                                                                                         ",
-"%&&&&&&&%.               @&&&&&&%+                                                                                                                                                                                                                                                                          ",
-"%&&&&&&&&#              #&&&&&&%.                                                                                                                                                                                                                                                                           ",
-"@&&&&&&&&&@           .$&&&&&&#.                                                                                                                                                                                                                                                                            ",
-" $&&&&&&&&&$+       +$&&&&&&%+                                                                                                                                                                                                                                                                              ",
-"  +&&&&&&&&&&%#@@#$%&&&&&&&#.                      +.     .+    +@.     ++    .+   +++++          +.    .+     ++     +++++.    .++++.        +@.       .@+     .++++.    .+++++++       +.         +@.       .+@.    .++++.         ++.      ++.    .+.      .+@.    .+     +.  .+  .+.    .+  .+++++++    ",
-"   .$&&&&&&&&&&&&&&&&&&&%@                         $%.    %@  +&&%&%.  .$$    +&  .&&&&&&#       .%@    +&.    %&+    $&&&&&%.  @&&&&&%.    +&&%&%.   .%&%&&+   #&&&&&&@  +&&&&&&%.      &#       +&&%&%.    @&&%&%.  +&&&&&&@       $&%     +%&+   .$&@     @&&%&$.  $%    .%$  $%  +&%.   +%. +&&&&&&$.   ",
-"      +$%%&&&&&&&&&&%$@.                           +&#   #%  +&#   %%   $$    +&  .&+   @&@      .%@    +&.   +$&$    $$   .%%  @%   .%&.  .&$  .%$.  %%.  #&+  #&   .$&+ +&.            &#      +&#   $%.  @&#  .%%. +&.   $&+      $%&+    #%&+   .&%$    @&#  +%$  $%    .%#  $%  +&%$   +%. +&.         ",
-"         .++@###@@+.                                #&. .&+  $%.   .&@  $$    +&  .&+    %$      .%@    +&.   ##$%    $$    @&. @%     %$  $%.   @&. @&+    %$. #&    .%@ +&.            &#      %%    .&#  %%    .&@ +&.    &#      $#%$    $#&+   @%@%.   %%    @%+ $%    .%#  $%  +&+%+  +%. +&.         ",
-"                                                    .%$ $$  .&#     %%  $$    +&  .&+    %$      .%@    +&.  .%@+&+   $$    @&. @%     #&  &#     +. %%     #&. #&    .%@ +&.            &#     .&@     $$ +&+    .$$ +&.    %#      $#@&   +$@&+   $#.%@  +&@    .+. $%    .%#  $%  +& $$  +%. +&.         ",
-"                                                     @&#&.  .&@     $&  $$    +&  .&#+++#&+      .%%####$&.  +%. %$   $%.++@&$  @%     +&..&@        &$     @&+ #&++++$%. +&$###@        &#     +&+     #%.@&.     #% +&+ ..#&+      $#.&@  ##+&+  .&..$$  @&.        $&$###$&#  $%  +& +%@ +%. +&####+     ",
-"                                                      %&@   +&+     #&  $$    +&  .&%$$%%@       .%%####$&.  #$  #&   $&$$%&#.  @%     +&++&@        &#     +&+ #&$$%&%+  +&$$$$#        &#     @&.     #%.@&.     #%.+%%%%%%@       $# $% .$+.&+  @%  @%. @&.        $&$###$&#  $%  +&  #%.+%. +&$$$$@     ",
-"                                                      #&.   .&@     $%  $$    +&  .&#+.$%.       .%@    +&. .$%##$&+  $%.+@&@   @%     +&..&@        &$     @&. #&+++$$   +&+            &#     +&.     #% @&.     $$ +&#@@++        $# +&.+$.+&+  $%@#$&+ @&.        $%    .%#  $%  +&  .%@+%. +&.         ",
-"                                                      @&    .%#     &$  $$    +%  .&+  .%@       .%@    +&. +%$###&$  $$   $%   @%     $&  &$    .$+ $%     #%. #&   +&+  +&.            &#     .&@    .%$ +&@    .%# +&.            $# .%### +&+ .&####&# .&@    .$+ $%    .%#  $%  +&   @%@%. +&.         ",
-"                                                      @&     #%.   @&.  #%.   $%  .&+   $%       .%@    +&. @$.   #&  $$   +&+  @%    +&@  #&.   #&. +&+   .%@  #&   .%#  +&.            &#      $%    +&+  %%    @&+ +&.            $#  #&%+ +&+ @%    #%. %%    #%. $%    .%#  $%  +&   .$%%. +&.         ",
-"                                                      @&     .%%+.@&#   .%%++#&@  .&+   +&+      .%@    +&. $#    .&+ $$    %$  @&+++#&%.   $%+.#&#   #&@.+%%.  #&    @%. +&@+++++.      &$++++. .%%+.@%#   .%%..@&#  +&.            $#  +&$  +&+ %#    +&+ .%%+.#&#  $%    .%#  $%  +&    +&&. +&@++++.  %&",
-"                                                      @&      .$&&%@     +%&&&@   .&+    %$      .%@    +&..%+     %$ $$    @&. @&&&&%@     .$%&&#     @%&&$.   #&    .%@ +&&&&&&%+      &&&&&&$. .$&&%#     .$&&%@   +&.            $#  .%#  +&+.&.    .%#  .$&&&@   $%    .%#  $%  +&     $&. +&&&&&&%. &&"};
-
-
-const char *loopRepeat_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #323331",
-"@     c #4D4F4C",
-"#     c #646663",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BFC1BD",
-"..................",
-"..................",
-"..................",
-"...&%#......#%&...",
-"...&&&%+..+%&&&...",
-"...$%&&%..%&&%$...",
-".....$&&##&&$.....",
-"......%&%%&%......",
-"......$&&&&$......",
-"......$&&&&$......",
-"......%&%%&%......",
-".....$&&##&&$.....",
-"...$%&&%..%&&%$...",
-"...&&&%+..+%&&&...",
-"...&%#......#%&...",
-"..................",
-"..................",
-".................."};
-
-
-const char *loopBasic_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"......#%&&%#......",
-"....+%&&&&&&%+....",
-"....%&&&%%&&&%....",
-"...#&&%+..+%&&#...",
-"...%&&+....+&&%...",
-"...&&%......%&&...",
-"...&&%......%&&...",
-"...%&&+....+&&%...",
-"...#&&%+..+%&&#...",
-"....%&&&%%&&&%....",
-"....+%&&&&&&%+....",
-"......#%&&%#......",
-"..................",
-"..................",
-".................."};
-
-
-const char *loopOnce_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #323331",
-"@     c #4D4F4C",
-"#     c #646663",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BFC1BD",
-"..................",
-"..................",
-"..................",
-"......$%&&%#......",
-"....+&&&&&&&&+....",
-"...+&&&&$$&&&&+...",
-"...$&&$....$&&$...",
-"...%&&......%&%...",
-"..................",
-"..................",
-"...%&&+.....&&&...",
-"...#&&$....$&&#...",
-"....%&&&%$&&&%....",
-"....+%&&&&&&%+....",
-"......#%&&%#......",
-"..................",
-"..................",
-".................."};
-
-
-const char *loopOnceBar_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #393A38",
-"+     c #545553",
-"@     c #747673",
-"#     c #A3A5A2",
-"$     c #ADAFAC",
-"%     c #B5B7B4",
-"&     c #C7C9C6",
-"                  ",
-"                  ",
-"                  ",
-"      @$&%#@      ",
-"    .$&&&&&&$.    ",
-"    %&&#@@#&&$    ",
-"   @&&@    @&&@   ",
-"   %&# +%$+ #&$   ",
-"       %&&%       ",
-"       %&&%       ",
-"   $&# +%%+ #&$   ",
-"   @&&@    @&&@   ",
-"    $&&#@@#&&$    ",
-"    .$&&&&&&$.    ",
-"      @#&&#@      ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *oneshotBasic_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...$$$$$$$$$$$$...",
-"...&&&&&&&&&&&&...",
-"...&&&&&&&&&&&&...",
-"..................",
-"..................",
-".................."};
-
-
-const char *oneshotRetrig_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...$$$$$$$#@......",
-"...&&&&&&&&&&@....",
-"...&&&&&&&&&&&+...",
-"..........+$&&%...",
-"............%&&...",
-"............%&&...",
-"...........+&&%...",
-"...$$$$$$$%&&&#...",
-"...&&&&&&&&&&%....",
-"...&&&&&&&&%#.....",
-"..................",
-"..................",
-".................."};
-
-
-const char *oneshotPress_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...+%&%+..........",
-"...%&&&%..........",
-"...&&&&&..........",
-"...$&&&$..........",
-"...+$&$+..........",
-"..................",
-"...$$$$$$$$$$$$...",
-"...&&&&&&&&&&&&...",
-"...&&&&&&&&&&&&...",
-"..................",
-"..................",
-".................."};
-
-
-const char *oneshotEndless_xpm[] = {
-"18 18 6 1",
-"      c #242523",
-".     c #464745",
-"+     c #6D6F6C",
-"@     c #888A87",
-"#     c #ADAFAC",
-"$     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        .++.      ",
-"       @$$$$#.    ",
-"      @$$$$$$$.   ",
-"     .$$#. +$$@   ",
-"     +$$.   @$#   ",
-"     +$$    @$$   ",
-"     .$$+   #$#   ",
-"   @@@$$$@@#$$+   ",
-"   $$$$$$$$$$@    ",
-"   $$$$$$$$#+     ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *updirOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #332F2E",
-"+     c #54494A",
-"@     c #6B5A5C",
-"#     c #866C6B",
-"$     c #967B7A",
-"%     c #987D7C",
-"&     c #B18E8F",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        @@        ",
-"       #&&#       ",
-"     .#&&&&#.     ",
-"    .$&&&&&&$.    ",
-"    +@%&&&&%@+    ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"       ....       ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *updirOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #555150",
-"+     c #706465",
-"@     c #7D6B6E",
-"#     c #877373",
-"$     c #957978",
-"%     c #9F8382",
-"&     c #B18E8F",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        ##        ",
-"       #&&#       ",
-"     .$&&&&$.     ",
-"    .%&&&&&&%.    ",
-"    +@%&&&&%@+    ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"       ....       ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *pause_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #514E53",
-"+     c #5C4F61",
-"@     c #6F507E",
-"#     c #855098",
-"$     c #9551AE",
-"%     c #A652C5",
-"&     c #AE52D1",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"       #+              ",
-"       &%#.            ",
-"       &&&%@           ",
-"       &&&&&$+         ",
-"       &&&&&&&#.       ",
-"       &&&&&&&&%@      ",
-"       &&&&&&&&&&#     ",
-"       &&&&&&&&%@.     ",
-"       &&&&&&&#.       ",
-"       &&&&&$+         ",
-"       &&&%@           ",
-"       &&#.            ",
-"       $+              ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-
-const char *play_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #393534",
-"+     c #574B4C",
-"@     c #6E5B5A",
-"#     c #7C6663",
-"$     c #8C7170",
-"%     c #A48384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"       $.              ",
-"       &&@             ",
-"       &&&%+           ",
-"       &&&&&$.         ",
-"       &&&&&&&@        ",
-"       &&&&&&&&%+      ",
-"       &&&&&&&&&&#     ",
-"       &&&&&&&&%+      ",
-"       &&&&&&&#.       ",
-"       &&&&&$.         ",
-"       &&&%+           ",
-"       &&@             ",
-"       $.              ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-
-const char *rewindOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #393534",
-"+     c #574B4C",
-"@     c #6E5B5A",
-"#     c #7C6663",
-"$     c #8C7170",
-"%     c #A48384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                .$     ",
-"               @&&     ",
-"             +%&&&     ",
-"           .$&&&&&     ",
-"          @&&&&&&&     ",
-"        +%&&&&&&&&     ",
-"       #&&&&&&&&&&     ",
-"        +%&&&&&&&&     ",
-"         .#&&&&&&&     ",
-"           .$&&&&&     ",
-"             +%&&&     ",
-"               @&&     ",
-"                .$     ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-
-const char *rewindOn_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #514E53",
-"+     c #5C4F61",
-"@     c #6F507E",
-"#     c #855098",
-"$     c #9551AE",
-"%     c #A652C5",
-"&     c #AE52D1",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                +#     ",
-"              .#%&     ",
-"             @%&&&     ",
-"           +$&&&&&     ",
-"         .#&&&&&&&     ",
-"        @%&&&&&&&&     ",
-"       #&&&&&&&&&&     ",
-"       .@%&&&&&&&&     ",
-"         .#&&&&&&&     ",
-"           +$&&&&&     ",
-"             @%&&&     ",
-"              .#&&     ",
-"                +$     ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-
-// 18x18
-/*
-const unsigned char giada_icon[] = {
-   0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
-   0x3e, 0xf0, 0x01, 0x1e, 0xe0, 0x01, 0x0e, 0xc3, 0x01, 0x8e, 0xff, 0x01,
-   0x8e, 0xc1, 0x01, 0x8e, 0xc1, 0x01, 0x8e, 0xc7, 0x01, 0x0e, 0xc7, 0x01,
-   0x1e, 0xc0, 0x01, 0x3e, 0xf0, 0x01, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
-   0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 };
-*/
-
-const char *giada_icon[] = {
-"65 65 11 1",
-"      c None",
-".     c #000000",
-"+     c #000100",
-"@     c #FFFFFF",
-"#     c #FDFFFC",
-"$     c #CBCDC9",
-"%     c #292B28",
-"&     c #626461",
-"*     c #484A47",
-"=     c #888A87",
-"-     c #A7A9A6",
-"....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++....",
-".@@@#####################$%+++++++++++++%&&*%+++++++&##%+++++....",
-".@@#####################&++++++++++++=$#######-*+++++&$+++++++...",
-".@@####################&++++++++++%-############$*+++++++++++++..",
-"+#####################*++++++++++&################-++++++++++++%+",
-"+####################*++++++++++=##################$+++++++++++*+",
-"+###################*++++++++++$####################$++++++++++=+",
-"+##################=++++++++++-######################-+++++++++-+",
-"+#################$++++++++++=#######################=+++++++++$+",
-"+#################%+++++++++*########################*+++++++++#+",
-"+################*++++++++++#########################%++++++++*#+",
-"+###############-++++++++++=########################$+++++++++&#+",
-"+###############%+++++++++%#########################-+++++++++-#+",
-"+##############-++++++++++-#########################&+++++++++$#+",
-"+##############%+++++++++%##########################*+++++++++##+",
-"+#############-++++++++++-##########################+++++++++%##+",
-"+#############%++++++++++##########################$+++++++++*##+",
-"+############$++++++++++&##########################=+++++++++=##+",
-"+############=++++++++++$##########################&+++++++++-##+",
-"+############*+++++++++%###########################%+++++++++$##+",
-"+############++++++++++=###########################++++++++++###+",
-"+###########$++++++++++$##########################-+++++++++*###+",
-"+###########=++++++++++###########################=+++++++++&###+",
-"+###########*+++++++++%###########################*+++++++++-###+",
-"+###########%+++++++++&###########################++++++++++$###+",
-"+###########%+++++++++-##########################=++++++++++####+",
-"+###########++++++++++$##########################%+++++++++%####+",
-"+###########++++++++++##########################$++++++++++&####+",
-"+##########$++++++++++##########################&++++++++++=####+",
-"+##########$+++++++++%#########################$+++++++++++-####+",
-"+##########$+++++++++%#########################&+++++++++++$####+",
-"+###########+++++++++*########################$++++++++++++#####+",
-"+###########+++++++++*########################*+++++++++++*#####+",
-"+###########%++++++++%#######################=++++++++++++&#####+",
-"+###########&+++++++++######################$+++++++++++++-#####+",
-"+###########=+++++++++$#####################%+++%+++++++++$#####+",
-"+###########$+++++++++$####################&+++%=+++++++++######+",
-"+############%++++++++&###################=++++$&++++++++%######+",
-"+############-+++++++++$#################&++++=#*++++++++&######+",
-"+#############+++++++++&################*++++*##+++++++++=######+",
-"+#############=+++++++++-#############$%++++%###+++++++++-######+",
-"+##############*+++++++++=##########$*+++++%###$+++++++++#######+",
-"+###############++++++++++&$######$&++++++&####=+++++++++#######+",
-"+###############$++++++++++++%&*%++++++++=#####&++++++++*#######+",
-"+################$%+++++++++++++++++++++-######%++++++++=#######+",
-"+##################&++++++++++++++++++=########+++++++++-#######+",
-"+###################$%+++++++++++++%=#########$+++++++++########+",
-"+#####################$=%++++++%*=-###########=++++++++%########+",
-"+##########################$$$################*++++++++&########+",
-"+#############################################+++++++++=########+",
-"+############################################$+++++++++$########+",
-"+############################################&++++++++%#########+",
-"+############################################+++++++++=#########+",
-"+###########################################=+++++++++##########+",
-"+###########################################%++++++++*##########+",
-"+##########################################=+++++++++-##########+",
-"+#########-==$############################$+++++++++&###########+",
-"+#######=++++++-##########################*+++++++++############+",
-"+######$++++++++$########################=+++++++++-############+",
-"+######=+++++++++$######################-+++++++++&#############+",
-"+######=+++++++++*#####################$+++++++++&##############.",
-".@#####=++++++++++-###################-+++++++++=##############@.",
-".@@####=++++++++++%##################=+++++++++=#############@@@.",
-".@@@###=+++++++++++*###############$*++++++++%$##############@@@.",
-"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....."};
-
-const char *recOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #342F2E",
-"+     c #3F3B3A",
-"@     c #594F4F",
-"#     c #7A6663",
-"$     c #8C7170",
-"%     c #A68384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"         @$%%$@        ",
-"       .$&&&&&&$.      ",
-"       $&&&&&&&&$      ",
-"      @&&&#++#&&&@     ",
-"      $&&#    #&&$     ",
-"      %&&+    +&&%     ",
-"      %&&+    +&&%     ",
-"      $&&#    #&&$     ",
-"      @&&&#++#&&&@     ",
-"       $&&&&&&&&$      ",
-"       .$&&&&&&$.      ",
-"         @$%%$@        ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-const char *recOn_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #5F4E50",
-"+     c #6E4F50",
-"@     c #8C5050",
-"#     c #AE5454",
-"$     c #BB5253",
-"%     c #C55352",
-"&     c #E85557",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"         @$&&$@        ",
-"       .%&&&&&&%.      ",
-"       %&&&&&&&&%      ",
-"      @&&&#++#&&&@     ",
-"      $&&#    #&&$     ",
-"      &&&+    +&&&     ",
-"      &&&+    +&&&     ",
-"      $&&#    #&&$     ",
-"      @&&&#++#&&&@     ",
-"       %&&&&&&&&%      ",
-"       .%&&&&&&%.      ",
-"         @$&&$@        ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-const char *inputRecOn_xpm[] = {
-"23 23 8 1",
-"      c #524D4C",
-".     c #4D4F4C",
-"+     c #5D4F50",
-"@     c #8C5050",
-"#     c #BB5253",
-"$     c #C45251",
-"%     c #DD5256",
-"&     c #EA5657",
-".......................",
-".......................",
-".......................",
-".......................",
-".......................",
-"........ @#%%#@ .......",
-".......+$&&&&&&$+......",
-"...... $&&&&&&&&$ .....",
-"......@&&&&&&&&&&@.....",
-"......#&&&&&&&&&&#.....",
-"......%&&&&&&&&&&%.....",
-"......%&&&&&&&&&&%.....",
-"......#&&&&&&&&&&#.....",
-"......@&&&&&&&&&&@.....",
-".......$&&&&&&&&$......",
-".......+$&&&&&&$+......",
-"........ @#%%#@ .......",
-".......................",
-".......................",
-".......................",
-".......................",
-".......................",
-"......................."};
-
-const char *inputRecOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #252724",
-"+     c #332F2E",
-"@     c #594E4F",
-"#     c #896E6D",
-"$     c #8D7271",
-"%     c #A68384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"        .@#%%#@.       ",
-"       +$&&&&&&$+      ",
-"      .$&&&&&&&&$.     ",
-"      @&&&&&&&&&&@     ",
-"      #&&&&&&&&&&#     ",
-"      %&&&&&&&&&&%     ",
-"      %&&&&&&&&&&%     ",
-"      #&&&&&&&&&&#     ",
-"      @&&&&&&&&&&@     ",
-"       $&&&&&&&&$      ",
-"       +$&&&&&&$+      ",
-"        .@#%%#@.       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
-const char *muteOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #2E2F2D",
-"+     c #3B3C3A",
-"@     c #525451",
-"#     c #6F716E",
-"$     c #878986",
-"%     c #ADAFAC",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ++.  .++     ",
-"    +&&$  $&&+    ",
-"    +&&%  %&&+    ",
-"    +&%&++&%&+    ",
-"    +&$&##&$&+    ",
-"    +&#%$$%#&+    ",
-"    +&#$%%$#&+    ",
-"    +&#@&&@#&+    ",
-"    +&#+&&+#&+    ",
-"    .#@ ## @#.    ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-const char *muteOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #585A57",
-"+     c #616260",
-"@     c #7A7C79",
-"#     c #888A87",
-"$     c #989A97",
-"%     c #B2B4B1",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ..    ..     ",
-"    +&&$  $&&+    ",
-"    +&&%  %&&+    ",
-"    +&%&++&%&+    ",
-"    +&$&@@&$&+    ",
-"    +&#%$$%#&+    ",
-"    +&#$&&$#&+    ",
-"    +&#@&&@#&+    ",
-"    +&#.&&.#&+    ",
-"    .#+ ## +#.    ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *readActionOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #393B38",
-"+     c #555754",
-"@     c #6B6D6A",
-"#     c #7F807E",
-"$     c #9C9E9B",
-"%     c #B1B3B0",
-"&     c #C3C5C2",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ....         ",
-"     %&&&&%+      ",
-"     %&@@@&&      ",
-"     %%   $&.     ",
-"     %&@@#&$      ",
-"     %&&&&@       ",
-"     %% +&$       ",
-"     %%  #&#      ",
-"     %%   %&+     ",
-"     @@   .#+     ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *readActionOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #696B68",
-"+     c #7A7C79",
-"@     c #888A87",
-"#     c #939592",
-"$     c #A7A9A6",
-"%     c #B7B9B6",
-"&     c #C4C6C3",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     %&&&&%.      ",
-"     %&++@&&      ",
-"     %%   $&      ",
-"     %&@@#&$      ",
-"     %&&&&@       ",
-"     %% +&$       ",
-"     %%  #&#      ",
-"     %%   %&.     ",
-"     +@   .@+     ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *metronomeOff_xpm[] = {
-"13 13 8 1",
-"      c #242523",
-".     c #2D2928",
-"+     c #34302F",
-"@     c #443D3C",
-"#     c #4F4445",
-"$     c #685659",
-"%     c #826A68",
-"&     c #A18282",
-"             ",
-"             ",
-"  .       .  ",
-" #%       %# ",
-" .&+     +&. ",
-"  %$     $%  ",
-"  @&     &@  ",
-"   &@   @&   ",
-"   $%   %$   ",
-"   +&. .&+   ",
-"    %# #%    ",
-"    .   .    ",
-"             "};
-
-
-const char *metronomeOn_xpm[] = {
-"13 13 8 1",
-"      c #4D4F4C",
-".     c #565150",
-"+     c #645C5C",
-"@     c #716465",
-"#     c #837070",
-"$     c #8F7775",
-"%     c #977C7B",
-"&     c #A68787",
-"             ",
-"             ",
-"  .       .  ",
-" @%       %@ ",
-" .&.     .&. ",
-"  $#     #$  ",
-"  +&     &+  ",
-"   &+   +&   ",
-"   #$   $#   ",
-"   .&. .&.   ",
-"    %@ @%    ",
-"    .   .    ",
-"             "};
-
-
-const char *zoomInOff_xpm[] = {
-"18 18 8 1",
-"      c None",
-".     c #252525",
-"+     c #262626",
-"@     c #535353",
-"#     c #ACACAC",
-"$     c #AEAEAE",
-"%     c #B1B1B1",
-"&     c #C4C4C4",
-"++++++++++++++++++",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+.......@@.......+",
-"+.......#$.......+",
-"+.......#$.......+",
-"+....@%%&&%%@....+",
-"+....@%%&&%%@....+",
-"+.......#$.......+",
-"+.......#$.......+",
-"+.......@@.......+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"++++++++++++++++++"};
-
-
-const char *zoomInOn_xpm[] = {
-"18 18 8 1",
-"      c None",
-".     c #4E4E4E",
-"+     c #707070",
-"@     c #717171",
-"#     c #B3B3B3",
-"$     c #B5B5B5",
-"%     c #B7B7B7",
-"&     c #C5C5C5",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"........++........",
-"........#$........",
-"........#$........",
-".....@%%&&%%@.....",
-".....@%%&&%%@.....",
-"........#$........",
-"........#$........",
-"........++........",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
-
-const char *zoomOutOff_xpm[] = {
-"18 18 5 1",
-"      c None",
-".     c #252525",
-"+     c #262626",
-"@     c #9C9C9C",
-"#     c #BBBBBB",
-"++++++++++++++++++",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+......@##@......+",
-"+......@##@......+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"++++++++++++++++++"};
-
-
-const char *zoomOutOn_xpm[] = {
-"18 18 4 1",
-"      c None",
-".     c #4E4E4E",
-"+     c #A7A7A7",
-"@     c #BEBEBE",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".......+@@+.......",
-".......+@@+.......",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
-
-
-const char *scrollRightOff_xpm[] = {
-"12 12 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #2E2F2D",
-"@     c #4D4F4C",
-"#     c #5D5F5C",
-"$     c #828481",
-"%     c #9B9D9A",
-"&     c #BCBEBB",
-"............",
-"............",
-"...+........",
-"...&$@......",
-"...$&&%@....",
-"....+#%&%...",
-"....+#%&%...",
-"...$&&%#....",
-"...&$@......",
-"...+........",
-"............",
-"............"};
-
-
-const char *scrollLeftOff_xpm[] = {
-"12 12 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #2E2F2D",
-"@     c #4D4F4C",
-"#     c #5D5F5C",
-"$     c #828481",
-"%     c #9B9D9A",
-"&     c #BCBEBB",
-"............",
-"............",
-"........+...",
-"......@$&...",
-"....@%&&$...",
-"...%&%#+....",
-"...%&%#+....",
-"....#%&&$...",
-"......@$&...",
-"........+...",
-"............",
-"............"};
-
-
-const char *scrollLeftOn_xpm[] = {
-"12 12 8 1",
-"      c #4D4F4C",
-".     c #6B6D6A",
-"+     c #7B7D7A",
-"@     c #969895",
-"#     c #A6A8A5",
-"$     c #B4B6B3",
-"%     c #C0C2BF",
-"&     c #FEFFFC",
-"            ",
-"            ",
-"            ",
-"      .@$   ",
-"    +#%%@   ",
-"   $%#+     ",
-"   %%#+     ",
-"    +$%%@   ",
-"      .#$   ",
-"            ",
-"            ",
-"            "};
-
-
-const char *scrollRightOn_xpm[] = {
-"12 12 8 1",
-"      c #4D4F4C",
-".     c #6B6D6A",
-"+     c #7B7D7A",
-"@     c #969895",
-"#     c #A6A8A5",
-"$     c #B4B6B3",
-"%     c #C0C2BF",
-"&     c #FEFFFC",
-"            ",
-"            ",
-"            ",
-"   %@.      ",
-"   @%%#.    ",
-"     +#%#   ",
-"     +#%#   ",
-"   @%%#+    ",
-"   %@.      ",
-"            ",
-"            ",
-"            "};
-
-
-const char *soloOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #616360",
-"+     c #737572",
-"@     c #838582",
-"#     c #929491",
-"$     c #A5A7A4",
-"%     c #B1B3B0",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .@+.       ",
-"      #&&&&#      ",
-"     .&$  %&.     ",
-"      &%+ ..      ",
-"      #&&&$.      ",
-"       .@$&&.     ",
-"     .#.  @&@     ",
-"     .&$. #&+     ",
-"      #&&&&$      ",
-"       .+@+       ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *soloOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #3D3F3D",
-"+     c #525451",
-"@     c #666865",
-"#     c #80827F",
-"$     c #979996",
-"%     c #A7A9A6",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .@@.       ",
-"      #&&&&#      ",
-"     .&$  %&.     ",
-"      &%+ ..      ",
-"      #&&&$+      ",
-"       .@%&&.     ",
-"     +#.  @&@     ",
-"     .&$..#&+     ",
-"      #&&&&$      ",
-"       .@@+       ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-#ifdef WITH_VST
-
-
-const char *fxOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #40423F",
-"+     c #4D4E4C",
-"@     c #686A67",
-"#     c #7B7D7A",
-"$     c #919390",
-"%     c #AEB0AD",
-"&     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"   ..... .   .    ",
-"   $&&&$ $% @&.   ",
-"   $$    .&#&@    ",
-"   $%##.  @&$     ",
-"   $%##.  #&%     ",
-"   $$    .&@&#    ",
-"   $$    %$ @&.   ",
-"   ..    +   +.   ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *fxOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #565855",
-"+     c #636562",
-"@     c #80827F",
-"#     c #8E908D",
-"$     c #9FA19E",
-"%     c #B1B3B0",
-"&     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"   .++++ +.  +.   ",
-"   $&&&$ $% @&.   ",
-"   $$    .&#&@    ",
-"   $%##+  @&$     ",
-"   $%##+  #&%     ",
-"   $$    +&@&#    ",
-"   $$    %$ @&+   ",
-"   ++   .+.  ++   ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *fxShiftUpOff_xpm[] = {
-"18 18 7 1",
-"      c #242523",
-".     c #4D4F4C",
-"+     c #A3A5A2",
-"@     c #868885",
-"#     c #C1C3C0",
-"$     c #313330",
-"%     c #626361",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .+@        ",
-"       @+#.       ",
-"      $#%+@       ",
-"      %# %#$      ",
-"      +@ $#%      ",
-"     $#.  @+      ",
-"     $.   $.      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *fxShiftUpOn_xpm[] = {
-"18 18 5 1",
-"      c #4D4F4C",
-".     c #70726F",
-"+     c #A5A7A4",
-"@     c #C1C3BF",
-"#     c #8E908D",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .++        ",
-"       +@@.       ",
-"       @.+#       ",
-"      .@ .@       ",
-"      +#  @.      ",
-"     .@.  #+      ",
-"      .    .      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *fxShiftDownOff_xpm[] = {
-"18 18 7 1",
-"      c #242523",
-".     c #4D4F4C",
-"+     c #A3A5A2",
-"@     c #313330",
-"#     c #626361",
-"$     c #868885",
-"%     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     .+@  #$      ",
-"     @%#  +$      ",
-"      $+ .%@      ",
-"      .%@$+       ",
-"       +$%#       ",
-"       #%%@       ",
-"       @..        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *fxShiftDownOn_xpm[] = {
-"18 18 5 1",
-"      c #4D4F4C",
-".     c #70726F",
-"+     c #A5A7A4",
-"@     c #C1C3BF",
-"#     c #8E908D",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     .+   .+      ",
-"      @.  +#      ",
-"      #+ .@.      ",
-"      .@.#+       ",
-"       +#@.       ",
-"       #@@        ",
-"        ..        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
-
-const char *vstLogo_xpm[] = {
-"65 38 8 1",
-"      c #161715",
-".     c #2B2D2A",
-"+     c #474846",
-"@     c #6A6C69",
-"#     c #8C8E8B",
-"$     c #A8AAA7",
-"%     c #C7C9C6",
-"&     c #EEF0ED",
-" @#############################################################+ ",
-"@#.............................................................$+",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                             ......      ..                  .#",
-"#.                         .@$$$####$%$#@.+&$                  .#",
-"#.                       .#$$#+.     +#$%%%%$                  .#",
-"#.                      .$$#$          .#$$%$                  .#",
-"#. .............    ....$$$$$          ++$$%$+@@@@@@@@@@@@@@@  .#",
-"#. ##$$$$$$%%%%@    %%&&&&%%$@         %&@#$$@@$%%&&&%%%&&&&&  .#",
-"#.   +$$$$$%@         .&%####%$@       $&$.$#  #$%%%&    @&%&  .#",
-"#.    +$$$$$%         +&$###$%%&&$@.   $&.     #$%%%&.    .%&  .#",
-"#.     @$$$$%$        %##$##$%&&&&&&%#.%#      #$$%%&.     @&  .#",
-"#.      $$$$$%+      #&  #$$%%&&&&&&&%%$$@     #$$%%&.      +  .#",
-"#.      .$$$$$%     +&+   .#%&&&&&&&&%$$#$$#   #$$%%&.         .#",
-"#.       @$$$$%$    %$       @%&&&&&&%$$###$$  #$$%%&.         .#",
-"#.        #$$$%%@  #&  .        +$&&&%$####$%$ #$$%%&.         .#",
-"#.         $$$%%% .&@ +%#          .@$$$###$$% #$$$%&.         .#",
-"#.         +%$%%%$$%  +$$+             #$#$$$% @$$$%&.         .#",
-"#.          #%%%%%&.  +%$$              ##$$%$ @$$$%%.         .#",
-"#.           $$%%%@   +%$$$.            #$$$%. @$$$$%.         .#",
-"#.           +%%%$    +%$$#$@          +$$%$   @#$$$%+         .#",
-"#.            @%%.    +%%%$$$$#@++.++@#$$$@ @@##$$$%%%$$@      .#",
-"#.             #@     +&#  .@@###$$$###@.   @+++@@@@###$@      .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                   .@$$$$$$$$  .$%%%%%%#                     .#",
-"#.                  .......      .@@@@@@@@@.                   .#",
-"#.                 ........   @@@+@@@@@@@@@@+                  .#",
-"@#                .........  .####@@@@@@@@@@@+                 #@",
-" @$$$$$$$$$$$$$$$..........  .@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$@ ",
-"                  .........  .@@@@@@@@@@@@@@@.                   ",
-"                   ........       @@@@@@@@@@.                    ",
-"                    ...........  .@@@@@@@@@                      ",
-"                     ..........  .@@@@@@@@                       "};
-
-
-const char *fxRemoveOff_xpm[] = {
-"18 18 9 1",
-"      c None",
-".     c #242623",
-"+     c #2F312E",
-"@     c #393A38",
-"#     c #484A47",
-"$     c #5D5F5C",
-"%     c #8E908D",
-"&     c #9B9D9A",
-"*     c #BDBFBC",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".....+#@..@#+.....",
-"......&*++*&......",
-"......@*%%*@......",
-".......$**$.......",
-".......#**#.......",
-"......+*&&*+......",
-"......%*@@*%......",
-"......@@..@@......",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
-
-const char *fxRemoveOn_xpm[] = {
-"18 18 9 1",
-"      c None",
-".     c #4D4F4C",
-"+     c #575956",
-"@     c #5C5D5B",
-"#     c #666865",
-"$     c #787977",
-"%     c #9C9E9B",
-"&     c #A6A8A5",
-"*     c #BFC1BE",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"......#@..@#......",
-"......&*++*&......",
-"......@*%%*@......",
-".......$**$.......",
-".......#**#.......",
-"......+*&&*+......",
-"......%*@+*%......",
-"......@+..+@......",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-#endif // #ifdef WITH_VST
-
-
-const char *beatsDivideOn_xpm[] = {
-"13 13 13 1",
-"      c None",
-".     c #595B58",
-"+     c #5B5D5A",
-"@     c #5F615E",
-"#     c #686967",
-"$     c #737572",
-"%     c #787A77",
-"&     c #80827F",
-"*     c #8F918E",
-"=     c #959794",
-"-     c #9A9C99",
-";     c #C4C6C3",
-">     c #C7C9C6",
-".............",
-".............",
-".............",
-".............",
-".....#>#.....",
-"....+@%@+....",
-"...*>>>>>*...",
-"....+@%@+....",
-".....#>#.....",
-".............",
-".............",
-".............",
-"............."};
-
-
-const char *beatsDivideOff_xpm[] = {
-"13 13 13 1",
-"      c None",
-".     c #242523",
-"+     c #262825",
-"@     c #2D2E2C",
-"#     c #3A3B39",
-"$     c #494B48",
-"%     c #525451",
-"&     c #595B58",
-"*     c #5F615E",
-"=     c #787A77",
-"-     c #858784",
-";     c #C3C5C1",
-">     c #C7C9C6",
-".............",
-".............",
-".............",
-"......+......",
-".....#>#.....",
-"...++@%@++...",
-"...=>>>>>=...",
-"...++@%@++...",
-".....#>#.....",
-"......+......",
-".............",
-".............",
-"............."};
-
-
-const char *beatsMultiplyOn_xpm[] = {
-"13 13 13 1",
-"      c None",
-".     c #595B58",
-"+     c #5B5D5A",
-"@     c #5F615E",
-"#     c #686967",
-"$     c #737572",
-"%     c #787A77",
-"&     c #80827F",
-"*     c #8F918E",
-"=     c #959794",
-"-     c #9A9C99",
-";     c #C4C6C3",
-">     c #C7C9C6",
-".............",
-".............",
-".............",
-"....$...$....",
-"...$;&.&;$...",
-"....&;-;&....",
-".....->-.....",
-"....&;=;&....",
-"...$;&.&;$...",
-"...+$...$....",
-".............",
-".............",
-"............."};
-
-
-const char *beatsMultiplyOff_xpm[] = {
-"13 13 12 1",
-"      c #242523",
-".     c #262825",
-"+     c #2D2E2C",
-"@     c #3A3B39",
-"#     c #494B48",
-"$     c #525451",
-"%     c #595B58",
-"&     c #5F615E",
-"*     c #787A77",
-"=     c #858784",
-"-     c #C3C5C1",
-";     c #C7C9C6",
-"             ",
-"             ",
-"             ",
-"   .#   #.   ",
-"   #-& &-#   ",
-"    &-=-&    ",
-"     =;=     ",
-"    %-*-&    ",
-"   #-% %-#   ",
-"   .#   #.   ",
-"             ",
-"             ",
-"             "};
diff --git a/src/graphics.h b/src/graphics.h
deleted file mode 100644 (file)
index c76da0f..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * graphics
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GRAPHICS_H
-#define GRAPHICS_H
-
-extern const char *giada_logo_xpm[];
-
-extern const char *loopRepeat_xpm[];
-extern const char *loopBasic_xpm[];
-extern const char *loopOnce_xpm[];
-extern const char *loopOnceBar_xpm[];
-extern const char *oneshotBasic_xpm[];
-extern const char *oneshotRetrig_xpm[];
-extern const char *oneshotPress_xpm[];
-extern const char *oneshotEndless_xpm[];
-
-extern const char *updirOff_xpm[];
-extern const char *updirOn_xpm[];
-
-extern const char *pause_xpm[];
-extern const char *play_xpm[];
-
-extern const char *zoomInOff_xpm[];
-extern const char *zoomInOn_xpm[];
-extern const char *zoomOutOff_xpm[];
-extern const char *zoomOutOn_xpm[];
-
-extern const char *scrollLeftOff_xpm[];
-extern const char *scrollLeftOn_xpm[];
-extern const char *scrollRightOff_xpm[];
-extern const char *scrollRightOn_xpm[];
-
-extern const char *rewindOff_xpm[];
-extern const char *rewindOn_xpm[];
-
-extern const char *recOff_xpm[];
-extern const char *recOn_xpm[];
-
-extern const char *metronomeOff_xpm[];
-extern const char *metronomeOn_xpm[];
-
-extern const char *inputRecOn_xpm[];
-extern const char *inputRecOff_xpm[];
-
-extern const char *beatsDivideOn_xpm[];
-extern const char *beatsDivideOff_xpm[];
-extern const char *beatsMultiplyOn_xpm[];
-extern const char *beatsMultiplyOff_xpm[];
-
-extern const char *muteOff_xpm[];
-extern const char *muteOn_xpm[];
-
-extern const char *soloOff_xpm[];
-extern const char *soloOn_xpm[];
-
-extern const char *readActionOn_xpm[];
-extern const char *readActionOff_xpm[];
-
-#ifdef WITH_VST
-extern const char *fxOff_xpm[];
-extern const char *fxOn_xpm[];
-
-extern const char *fxShiftUpOn_xpm[];
-extern const char *fxShiftUpOff_xpm[];
-extern const char *fxShiftDownOn_xpm[];
-extern const char *fxShiftDownOff_xpm[];
-
-extern const char *fxRemoveOff_xpm[];
-extern const char *fxRemoveOn_xpm[];
-
-extern const char *vstLogo_xpm[];
-#endif
-
-extern const char *giada_icon[];
-
-#endif
diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp
new file mode 100644 (file)
index 0000000..e790253
--- /dev/null
@@ -0,0 +1,126 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_about
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../core/kernelAudio.h"
+#include "../../core/kernelMidi.h"
+#include "../../core/graphics.h"
+#include "../../utils/gui_utils.h"
+#include "../elems/ge_mixed.h"
+#include "gd_about.h"
+
+
+extern Conf G_Conf;
+
+
+gdAbout::gdAbout()
+#ifdef WITH_VST
+: gWindow(340, 405, "About Giada") {
+#else
+: gWindow(340, 320, "About Giada") {
+#endif
+
+       if (G_Conf.aboutX)
+               resize(G_Conf.aboutX, G_Conf.aboutY, w(), h());
+
+       set_modal();
+
+       logo  = new gBox(8, 10, 324, 86);
+       text  = new gBox(8, 120, 324, 145);
+       close = new gClick(252, h()-28, 80, 20, "Close");
+#ifdef WITH_VST
+       vstLogo = new gBox(8, 265, 324, 50);
+       vstText = new gBox(8, 315, 324, 46);
+#endif
+       end();
+
+       logo->image(new Fl_Pixmap(giada_logo_xpm));
+       text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
+
+       char message[512];
+       sprintf(
+         message,
+         "Version " VERSIONE " (" __DATE__ ")\n\n"
+               "Developed by Monocasual\n"
+               "Based on FLTK (%d.%d.%d), RtAudio (%s),\n"
+               "RtMidi (%s), libsamplerate and libsndfile\n\n"
+               "Released under the terms of the GNU General\n"
+               "Public License (GPL v3)\n\n"
+               "News, infos, contacts and documentation:\n"
+               "www.giadamusic.com",
+               FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, 
+               kernelAudio::getRtAudioVersion().c_str(),
+               kernelMidi::getRtMidiVersion().c_str());
+
+       int tw = 0;
+       int th = 0;
+       fl_measure(message, tw, th);
+       text->copy_label(message);
+       text->size(text->w(), th);
+
+#ifdef WITH_VST
+       vstLogo->image(new Fl_Pixmap(vstLogo_xpm));
+       vstLogo->position(vstLogo->x(), text->y()+text->h()+8);
+       vstText->label(
+               "VST Plug-In Technology by Steinberg\n"
+               "VST is a trademark of Steinberg\nMedia Technologies GmbH"
+       );
+       vstText->position(vstText->x(), vstLogo->y()+vstLogo->h());
+
+#endif
+
+       close->callback(cb_close, (void*)this);
+       gu_setFavicon(this);
+       setId(WID_ABOUT);
+       show();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdAbout::~gdAbout() {
+       G_Conf.aboutX = x();
+       G_Conf.aboutY = y();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdAbout::cb_close(Fl_Widget *w, void *p) { ((gdAbout*)p)->__cb_close(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdAbout::__cb_close() {
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_about.h b/src/gui/dialogs/gd_about.h
new file mode 100644 (file)
index 0000000..91f5065
--- /dev/null
@@ -0,0 +1,58 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_about
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_ABOUT_H
+#define GD_ABOUT_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../elems/ge_window.h"
+
+
+class gdAbout : public gWindow {
+private:
+       class gBox       *logo;
+       class gBox       *text;
+       class gClick *close;
+
+#ifdef WITH_VST
+       class gBox  *vstText;
+       class gBox  *vstLogo;
+#endif
+
+public:
+       gdAbout();
+       ~gdAbout();
+
+       static void cb_close(Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp
new file mode 100644 (file)
index 0000000..5d5edc2
--- /dev/null
@@ -0,0 +1,472 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_actionEditor
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <math.h>
+#include "../../utils/gui_utils.h"
+#include "../../core/graphics.h"
+#include "../../core/mixer.h"
+#include "../../core/recorder.h"
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../elems/ge_actionChannel.h"
+#include "../elems/ge_muteChannel.h"
+#include "../elems/ge_envelopeChannel.h"
+#include "../elems/ge_pianoRoll.h"
+#include "../elems/ge_mixed.h"
+#include "gd_actionEditor.h"
+
+
+extern Mixer G_Mixer;
+extern Conf     G_Conf;
+
+
+gdActionEditor::gdActionEditor(Channel *chan)
+       :       gWindow(640, 284),
+               chan   (chan),
+               zoom   (100),
+               coverX (0)
+{
+       if (G_Conf.actionEditorW) {
+               resize(G_Conf.actionEditorX, G_Conf.actionEditorY, G_Conf.actionEditorW, G_Conf.actionEditorH);
+               zoom = G_Conf.actionEditorZoom;
+       }
+
+       totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom);
+
+       /* container with zoom buttons and the action type selector. Scheme of
+        * the resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
+
+       Fl_Group *upperArea = new Fl_Group(8, 8, w()-16, 20);
+
+       upperArea->begin();
+
+       if (chan->type == CHANNEL_SAMPLE) {
+         actionType = new gChoice(8, 8, 80, 20);
+         gridTool   = new gGridTool(actionType->x()+actionType->w()+4, 8, this);
+               actionType->add("key press");
+               actionType->add("key release");
+               actionType->add("kill chan");
+               actionType->value(0);
+
+               SampleChannel *ch = (SampleChannel*) chan;
+               if (ch->mode == SINGLE_PRESS || ch->mode & LOOP_ANY)
+               actionType->deactivate();
+       }
+       else {
+               gridTool = new gGridTool(8, 8, this);
+       }
+
+               gBox *b1   = new gBox(gridTool->x()+gridTool->w()+4, 8, 300, 20);    // padding actionType - zoomButtons
+               zoomIn     = new gClick(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+               zoomOut    = new gClick(w()-8-20,   8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
+       upperArea->end();
+       upperArea->resizable(b1);
+
+       zoomIn->callback(cb_zoomIn, (void*)this);
+       zoomOut->callback(cb_zoomOut, (void*)this);
+
+       /* main scroller: contains all widgets */
+
+       scroller = new gScroll(8, 36, w()-16, h()-44);
+
+       if (chan->type == CHANNEL_SAMPLE) {
+
+               SampleChannel *ch = (SampleChannel*) chan;
+
+               ac = new gActionChannel     (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch);
+               mc = new gMuteChannel       (scroller->x(), ac->y()+ac->h()+8, this);
+               vc = new gEnvelopeChannel   (scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume");
+               scroller->add(ac);
+               //scroller->add(new gResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8));
+               scroller->add(mc);
+               //scroller->add(new gResizerBar(mc->x(), mc->y()+mc->h(), scroller->w(), 8));
+               scroller->add(vc);
+               //scroller->add(new gResizerBar(vc->x(), vc->y()+vc->h(), scroller->w(), 8));
+
+               /* fill volume envelope with actions from recorder */
+
+               vc->fill();
+
+               /* if channel is LOOP_ANY, deactivate it: a loop mode channel cannot
+                * hold keypress/keyrelease actions */
+
+               if (ch->mode & LOOP_ANY)
+                       ac->deactivate();
+       }
+       else {
+               pr = new gPianoRollContainer(scroller->x(), upperArea->y()+upperArea->h()+8, this);
+               scroller->add(pr);
+               scroller->add(new gResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8));
+       }
+
+       end();
+
+       /* compute values */
+
+       update();
+       gridTool->calc();
+
+       gu_setFavicon(this);
+
+       char buf[256];
+       sprintf(buf, "Edit Actions in Channel %d", chan->index+1);
+       label(buf);
+
+       set_non_modal();
+       size_range(640, 284);
+       resizable(scroller);
+
+       show();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdActionEditor::~gdActionEditor() {
+       G_Conf.actionEditorX = x();
+       G_Conf.actionEditorY = y();
+       G_Conf.actionEditorW = w();
+       G_Conf.actionEditorH = h();
+       G_Conf.actionEditorZoom = zoom;
+
+       /** CHECKME - missing clear() ? */
+
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdActionEditor::cb_zoomIn(Fl_Widget *w, void *p)  { ((gdActionEditor*)p)->__cb_zoomIn(); }
+void gdActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomOut(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdActionEditor::__cb_zoomIn() {
+
+       /* zoom 50: empirical value, to avoid a totalWidth > 16 bit signed
+        * (32767 max), unsupported by FLTK 1.3.x */
+
+       if (zoom <= 50)
+               return;
+
+       zoom /= 2;
+
+       update();
+
+       if (chan->type == CHANNEL_SAMPLE) {
+               ac->size(totalWidth, ac->h());
+               mc->size(totalWidth, mc->h());
+               vc->size(totalWidth, vc->h());
+               ac->updateActions();
+               mc->updateActions();
+               vc->updateActions();
+       }
+       else {
+               pr->size(totalWidth, pr->h());
+               pr->updateActions();
+       }
+
+       /* scroll to pointer */
+
+       int shift = Fl::event_x() + scroller->xposition();
+       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
+
+       /* update all underlying widgets */
+
+       gridTool->calc();
+       scroller->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdActionEditor::__cb_zoomOut() {
+
+       zoom *= 2;
+
+       update();
+
+       if (chan->type == CHANNEL_SAMPLE) {
+               ac->size(totalWidth, ac->h());
+               mc->size(totalWidth, mc->h());
+               vc->size(totalWidth, vc->h());
+               ac->updateActions();
+               mc->updateActions();
+               vc->updateActions();
+       }
+       else {
+               pr->size(totalWidth, pr->h());
+               pr->updateActions();
+       }
+
+       /* scroll to pointer */
+
+       int shift = (Fl::event_x() + scroller->xposition()) / -2;
+       if (scroller->xposition() + shift < 0)
+                       shift = 0;
+       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
+
+       /* update all underlying widgets */
+
+       gridTool->calc();
+       scroller->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdActionEditor::update() {
+       totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom);
+       if (totalWidth < scroller->w()) {
+               totalWidth = scroller->w();
+               zoom = (int) ceilf(G_Mixer.framesInSequencer / (float) totalWidth);
+               scroller->scroll_to(0, scroller->yposition());
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gdActionEditor::handle(int e) {
+       int ret = Fl_Group::handle(e);
+       switch (e) {
+               case FL_MOUSEWHEEL: {
+                       Fl::event_dy() == -1 ? __cb_zoomIn() : __cb_zoomOut();
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gdActionEditor::getActionType() {
+       if (actionType->value() == 0)
+               return ACTION_KEYPRESS;
+       else
+       if (actionType->value() == 1)
+               return ACTION_KEYREL;
+       else
+       if (actionType->value() == 2)
+               return ACTION_KILLCHAN;
+       else
+               return -1;
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gGridTool::gGridTool(int x, int y, gdActionEditor *parent)
+       :       Fl_Group(x, y, 80, 20), parent(parent)
+{
+       gridType = new gChoice(x, y, 40, 20);
+       gridType->add("1");
+       gridType->add("2");
+       gridType->add("3");
+       gridType->add("4");
+       gridType->add("6");
+       gridType->add("8");
+       gridType->add("16");
+       gridType->add("32");
+       gridType->value(0);
+       gridType->callback(cb_changeType, (void*)this);
+
+       active = new gCheck (x+44, y+4, 12, 12);
+
+       gridType->value(G_Conf.actionEditorGridVal);
+       active->value(G_Conf.actionEditorGridOn);
+
+       end();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gGridTool::~gGridTool() {
+       G_Conf.actionEditorGridVal = gridType->value();
+       G_Conf.actionEditorGridOn  = active->value();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gGridTool::cb_changeType(Fl_Widget *w, void *p)  { ((gGridTool*)p)->__cb_changeType(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gGridTool::__cb_changeType() {
+       calc();
+       parent->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gGridTool::isOn() {
+       return active->value();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gGridTool::getValue() {
+       switch (gridType->value()) {
+               case 0: return 1;
+               case 1: return 2;
+               case 2: return 3;
+               case 3: return 4;
+               case 4: return 6;
+               case 5: return 8;
+               case 6: return 16;
+               case 7: return 32;
+       }
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gGridTool::calc() {
+
+       points.clear();
+       frames.clear();
+       bars.clear();
+       beats.clear();
+
+       /* find beats, bars and grid. The method is the same of the waveform in sample
+        * editor. Take totalwidth (the width in pixel of the area to draw), knowing
+        * that totalWidth = totalFrames / zoom. Then, for each pixel of totalwidth,
+        * put a concentrate of each block (which is totalFrames / zoom) */
+
+       int  j   = 0;
+       int fpgc = floor(G_Mixer.framesPerBeat / getValue());  // frames per grid cell
+
+       for (int i=1; i<parent->totalWidth; i++) {   // if i=0, step=0 -> useless cycle
+               int step = parent->zoom*i;
+               while (j < step && j < G_Mixer.totalFrames) {
+                       if (j % fpgc == 0) {
+                               points.add(i);
+                               frames.add(j);
+                       }
+                       if (j % G_Mixer.framesPerBeat == 0)
+                               beats.add(i);
+                       if (j % G_Mixer.framesPerBar == 0 && i != 1)
+                               bars.add(i);
+                       if (j == G_Mixer.totalFrames-1)
+                               parent->coverX = i;
+                       j++;
+               }
+               j = step;
+       }
+
+       /* fix coverX if == 0, which means G_Mixer.beats == 32 */
+
+       if (G_Mixer.beats == 32)
+               parent->coverX = parent->totalWidth;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gGridTool::getSnapPoint(int v) {
+
+       if (v == 0) return 0;
+
+       for (int i=0; i<(int)points.size; i++) {
+
+               if (i == (int) points.size-1)
+                       return points.at(i);
+
+               int gp  = points.at(i);
+               int gpn = points.at(i+1);
+
+               if (v >= gp && v < gpn)
+                       return gp;
+       }
+       return v;  // default value
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gGridTool::getSnapFrame(int v) {
+
+       v *= parent->zoom;  // transformation pixel -> frame
+
+       for (int i=0; i<(int)frames.size; i++) {
+
+               if (i == (int) frames.size-1)
+                       return frames.at(i);
+
+               int gf  = frames.at(i);     // grid frame
+               int gfn = frames.at(i+1);   // grid frame next
+
+               if (v >= gf && v < gfn) {
+
+                       /* which one is the closest? gf < v < gfn */
+
+                       if ((gfn - v) < (v - gf))
+                               return gfn;
+                       else
+                               return gf;
+               }
+       }
+       return v;  // default value
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gGridTool::getCellSize() {
+       return (parent->coverX - parent->ac->x()) / G_Mixer.beats / getValue();
+}
diff --git a/src/gui/dialogs/gd_actionEditor.h b/src/gui/dialogs/gd_actionEditor.h
new file mode 100644 (file)
index 0000000..1c38e7e
--- /dev/null
@@ -0,0 +1,131 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_actionEditor
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_ACTIONEDITOR_H
+#define GD_ACTIONEDITOR_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Scroll.H>
+#include "../elems/ge_window.h"
+
+
+/* gActionEditor
+ * main window which contains the tools for dealing with actions.
+ * This class calculates chan, zoom, frames per beat, and so on. Each
+ * sub-widget contains a pointer to this window to query those data. */
+
+class gdActionEditor : public gWindow {
+
+private:
+
+       /* update
+        * compute total width, in pixel. */
+
+       void update();
+
+public:
+
+       gdActionEditor(class Channel *chan);
+       ~gdActionEditor();
+
+       int handle(int e);
+
+       int getActionType();
+
+       static void cb_zoomIn(Fl_Widget *w, void *p);
+       static void cb_zoomOut(Fl_Widget *w, void *p);
+       inline void __cb_zoomIn();
+       inline void __cb_zoomOut();
+
+       class gChoice   *actionType;
+       class gGridTool *gridTool;
+       class gClick    *zoomIn;
+       class gClick    *zoomOut;
+       class gScroll   *scroller;       // widget container
+
+       class gActionChannel      *ac;
+       class gMuteChannel        *mc;
+       class gEnvelopeChannel    *vc;
+       class gPianoRollContainer *pr;
+
+       gVector <class gActionWidget*> widgets;
+
+       class Channel *chan;
+
+       int zoom;
+       int totalWidth;  // total width of the widget, in pixel (zoom affected)
+       int coverX;              // x1 of the unused area (x2 = totalWidth)
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gGridTool : public Fl_Group {
+
+private:
+       class gChoice  *gridType;
+       class gCheck   *active;
+
+       class gdActionEditor *parent;
+
+       static void cb_changeType(Fl_Widget *w, void *p);
+       inline void __cb_changeType();
+
+public:
+
+       gGridTool(int x, int y, gdActionEditor *parent);
+       ~gGridTool();
+
+       int  getValue();
+       bool isOn();
+       void calc();
+
+       /* getSnapPoint
+        * given a cursor position in input, return the x coordinates of the
+        * nearest snap point (in pixel, clean, ie. not x()-shifted) */
+
+       int getSnapPoint(int v);
+       int getSnapFrame(int v);
+
+       /* getCellSize
+        * return the size in pixel of a single cell of the grid. */
+
+       int getCellSize();
+
+       gVector<int> points;   // points of the grid
+       gVector<int> frames;   // frames of the grid
+
+       gVector<int> bars;
+       gVector<int> beats;
+};
+
+
+#endif
diff --git a/src/gui/dialogs/gd_beatsInput.cpp b/src/gui/dialogs/gd_beatsInput.cpp
new file mode 100644 (file)
index 0000000..bf7455f
--- /dev/null
@@ -0,0 +1,102 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_beatsInput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../utils/gui_utils.h"
+#include "../../core/patch.h"
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../glue/glue.h"
+#include "gd_beatsInput.h"
+#include "gd_mainWindow.h"
+
+
+extern Mixer                            G_Mixer;
+extern Conf          G_Conf;
+extern gdMainWindow *mainWin;
+
+
+gdBeatsInput::gdBeatsInput()
+       : gWindow(164, 60, "Beats")
+{
+       if (G_Conf.beatsX)
+               resize(G_Conf.beatsX, G_Conf.beatsY, w(), h());
+
+       set_modal();
+
+       beats     = new gInput(8,  8,  35, 20);
+       bars      = new gInput(47, 8,  35, 20);
+       ok                  = new gClick(86, 8,  70, 20, "Ok");
+       resizeRec = new gCheck(8,  40, 12, 12, "resize recorded actions");
+       end();
+
+       char buf_bars[3]; sprintf(buf_bars, "%d", G_Mixer.bars);
+       char buf_beats[3]; sprintf(buf_beats, "%d", G_Mixer.beats);
+       beats->maximum_size(2);
+       beats->value(buf_beats);
+       beats->type(FL_INT_INPUT);
+       bars->maximum_size(2);
+       bars->value(buf_bars);
+       bars->type(FL_INT_INPUT);
+       ok->shortcut(FL_Enter);
+       ok->callback(cb_update_batt, (void*)this);
+       resizeRec->value(G_Conf.resizeRecordings);
+
+       gu_setFavicon(this);
+       setId(WID_BEATS);
+       show();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdBeatsInput::~gdBeatsInput()
+{
+       G_Conf.beatsX = x();
+       G_Conf.beatsY = y();
+       G_Conf.resizeRecordings =       resizeRec->value();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdBeatsInput::cb_update_batt(Fl_Widget *w, void *p) { ((gdBeatsInput*)p)->__cb_update_batt(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdBeatsInput::__cb_update_batt()
+{
+       if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
+               return;
+       glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value());
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_beatsInput.h b/src/gui/dialogs/gd_beatsInput.h
new file mode 100644 (file)
index 0000000..2818c72
--- /dev/null
@@ -0,0 +1,56 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_beatsInput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GD_BEATSINPUT_H
+#define GD_BEATSINPUT_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../elems/ge_window.h"
+
+
+class gdBeatsInput : public gWindow
+{
+private:
+
+       static void cb_update_batt(Fl_Widget *w, void *p);
+       inline void __cb_update_batt();
+
+       class gInput *beats;
+       class gInput *bars;
+       class gClick *ok;
+       class gCheck *resizeRec;
+
+public:
+
+       gdBeatsInput();
+       ~gdBeatsInput();
+};
+
+
+#endif
diff --git a/src/gui/dialogs/gd_bpmInput.cpp b/src/gui/dialogs/gd_bpmInput.cpp
new file mode 100644 (file)
index 0000000..a10e35c
--- /dev/null
@@ -0,0 +1,105 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_bpmInput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../core/conf.h"
+#include "../../core/mixer.h"
+#include "../../glue/glue.h"
+#include "../../utils/gui_utils.h"
+#include "../elems/ge_mixed.h"
+#include "gd_bpmInput.h"
+#include "gd_mainWindow.h"
+
+
+extern Mixer                    G_Mixer;
+extern Conf          G_Conf;
+extern gdMainWindow *mainWin;
+
+
+gdBpmInput::gdBpmInput(const char *label)
+: gWindow(144, 36, "Bpm") {
+
+       if (G_Conf.bpmX)
+               resize(G_Conf.bpmX, G_Conf.bpmY, w(), h());
+
+       set_modal();
+
+       input_a = new gInput(8,  8, 30, 20);
+       input_b = new gInput(42, 8, 20, 20);
+       ok                = new gClick(66, 8, 70, 20, "Ok");
+       end();
+
+       char   a[4];
+       snprintf(a, 4, "%d", (int) G_Mixer.bpm);
+       char   b[2];
+       for (unsigned i=0; i<strlen(label); i++)        // looking for the dot
+               if (label[i] == '.') {
+                       snprintf(b, 2, "%c", label[i+1]);
+                       break;
+               }
+
+       input_a->maximum_size(3);
+       input_a->type(FL_INT_INPUT);
+       input_a->value(a);
+       input_b->maximum_size(1);
+       input_b->type(FL_INT_INPUT);
+       input_b->value(b);
+
+       ok->shortcut(FL_Enter);
+       ok->callback(cb_update_bpm, (void*)this);
+
+       gu_setFavicon(this);
+       setId(WID_BPM);
+       show();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdBpmInput::~gdBpmInput() {
+       G_Conf.bpmX = x();
+       G_Conf.bpmY = y();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdBpmInput::cb_update_bpm(Fl_Widget *w, void *p) { ((gdBpmInput*)p)->__cb_update_bpm(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdBpmInput::__cb_update_bpm() {
+       if (strcmp(input_a->value(), "") == 0)
+               return;
+       glue_setBpm(input_a->value(), input_b->value());
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_bpmInput.h b/src/gui/dialogs/gd_bpmInput.h
new file mode 100644 (file)
index 0000000..8a6a945
--- /dev/null
@@ -0,0 +1,51 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_bpmInput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GD_BPMINPUT_H
+#define GD_BPMINPUT_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../elems/ge_window.h"
+
+
+class gdBpmInput : public gWindow {
+private:
+       static void cb_update_bpm(Fl_Widget *w, void *p);
+       inline void __cb_update_bpm();
+
+       class gInput *input_a;
+       class gInput *input_b;
+       class gClick *ok;
+
+public:
+       gdBpmInput(const char *label); // pointer to mainWin->timing->bpm->label()
+       ~gdBpmInput();
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_browser.cpp b/src/gui/dialogs/gd_browser.cpp
new file mode 100644 (file)
index 0000000..d415ae0
--- /dev/null
@@ -0,0 +1,395 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_browser
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "../../core/graphics.h"
+#include "../../core/wave.h"
+#include "../../core/pluginHost.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/patch.h"
+#include "../../core/conf.h"
+#include "../../glue/glue.h"
+#include "../elems/ge_browser.h"
+#include "../elems/ge_channel.h"
+#include "../elems/ge_keyboard.h"
+#include "gd_browser.h"
+#include "gd_pluginList.h"
+#include "gd_mainWindow.h"
+#include "gd_warnings.h"
+
+
+extern Patch         G_Patch;
+extern Conf             G_Conf;
+extern Mixer         G_Mixer;
+#ifdef WITH_VST
+extern PluginHost    G_PluginHost;
+#endif
+extern gdMainWindow    *mainWin;
+
+
+gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int type, int stackType)
+       :       gWindow  (396, 302, title),
+               ch       (ch),
+               type     (type),
+               stackType(stackType)
+{
+       set_non_modal();
+
+       browser = new gBrowser(8, 36, 380, 230);
+       Fl_Group *group_btn = new Fl_Group(8, 274, 380, 20);
+               gBox *b = new gBox(8, 274, 204, 20);                                            // spacer window border <-> buttons
+               ok        = new gClick(308, 274, 80, 20);
+               cancel  = new gClick(220, 274, 80, 20, "Cancel");
+               status  = new gProgress(8, 274, 204, 20);
+               status->minimum(0);
+               status->maximum(1);
+               status->hide();   // show the bar only if necessary
+       group_btn->resizable(b);
+       group_btn->end();
+
+       Fl_Group *group_upd = new Fl_Group(8, 8, 380, 25);
+               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
+                       name = new gInput(208, 8, 152, 20);
+               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
+                       where = new gInput(8, 8, 192, 20);
+               else
+                       where = new gInput(8, 8, 352, 20);
+               updir   = new gClick(368, 8, 20, 20, "", updirOff_xpm, updirOn_xpm);
+       group_upd->resizable(where);
+       group_upd->end();
+
+       end();
+
+       resizable(browser);
+       size_range(w(), h(), 0, 0);
+
+       where->readonly(true);
+       where->cursor_color(COLOR_BG_DARK);
+
+       if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT)  /// bitmask please!
+               ok->label("Save");
+       else
+               ok->label("Load");
+
+       if (type == BROWSER_LOAD_PATCH)
+               ok->callback(cb_load_patch, (void*)this);
+       else
+       if (type == BROWSER_LOAD_SAMPLE)
+               ok->callback(cb_load_sample, (void*)this);
+       else
+       if (type == BROWSER_SAVE_PATCH) {
+               ok->callback(cb_save_patch, (void*)this);
+               name->value(G_Patch.name[0] == '\0' ? "my_patch.gptc" : G_Patch.name);
+               name->maximum_size(MAX_PATCHNAME_LEN+5); // +5 for ".gptc"
+       }
+       else
+       if (type == BROWSER_SAVE_SAMPLE) {
+               ok->callback(cb_save_sample, (void*)this);
+               name->value(((SampleChannel*)ch)->wave->name.c_str());
+       }
+       else
+       if (type == BROWSER_SAVE_PROJECT) {
+               ok->callback(cb_save_project, (void*)this);
+               name->value(gStripExt(G_Patch.name).c_str());
+       }
+#ifdef WITH_VST
+       else
+       if (type == BROWSER_LOAD_PLUGIN) {
+               ok->callback(cb_loadPlugin, (void*)this);
+       }
+#endif
+
+       ok->shortcut(FL_Enter);
+
+       updir->callback(cb_up, (void*)this);
+       cancel->callback(cb_close, (void*)this);
+       browser->callback(cb_down, this);
+       browser->path_obj = where;
+       browser->init(initPath);
+
+       if (G_Conf.browserW)
+               resize(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH);
+
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdBrowser::~gdBrowser() {
+       G_Conf.browserX = x();
+       G_Conf.browserY = y();
+       G_Conf.browserW = w();
+       G_Conf.browserH = h();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::cb_load_patch  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_load_patch();  }
+void gdBrowser::cb_load_sample (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_load_sample(); }
+void gdBrowser::cb_save_sample (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_sample(); }
+void gdBrowser::cb_save_patch  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_patch(); }
+void gdBrowser::cb_save_project(Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_save_project(); }
+void gdBrowser::cb_down        (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_down(); }
+void gdBrowser::cb_up          (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_up(); }
+void gdBrowser::cb_close       (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_close(); }
+#ifdef WITH_VST
+void gdBrowser::cb_loadPlugin  (Fl_Widget *v, void *p)  { ((gdBrowser*)p)->__cb_loadPlugin(); }
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_load_patch() {
+
+       if (browser->text(browser->value()) == NULL)
+               return;
+
+       /* patchFile is the file to open.
+        * For patches:  browser->get_selected_item()
+        * for projects: browser->get_selected_item() without extention +
+        *               patch name appended */
+
+       std::string patchFile = browser->get_selected_item();;
+       bool        isProject;
+
+       if (gIsProject(browser->get_selected_item())) {
+               std::string patchName = gGetProjectName(browser->get_selected_item());
+#if defined(__linux__) || defined(__APPLE__)
+               patchFile = patchFile+"/"+patchName+".gptc";
+#elif defined(_WIN32)
+               patchFile = patchFile+"\\"+patchName+".gptc";
+#endif
+               isProject = true;
+       }
+       else
+               isProject = false;
+
+       int res = glue_loadPatch(patchFile.c_str(),     browser->path_obj->value(),     status, isProject);
+
+       if (res == PATCH_UNREADABLE) {
+               status->hide();
+               if (isProject)
+                       gdAlert("This project is unreadable.");
+               else
+                       gdAlert("This patch is unreadable.");
+       }
+       else if (res == PATCH_INVALID) {
+               status->hide();
+               if (isProject)
+                       gdAlert("This project is not valid.");
+               else
+                       gdAlert("This patch is not valid.");
+       }
+       else
+               do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_save_sample() {
+
+       if (strcmp(name->value(), "") == 0) {    /// FIXME glue business
+               gdAlert("Please choose a file name.");
+               return;
+       }
+
+       /* bruteforce check extension. */
+
+       std::string filename = gStripExt(name->value());
+       char fullpath[PATH_MAX];
+       sprintf(fullpath, "%s/%s.wav", where->value(), filename.c_str());
+
+       if (gFileExists(fullpath))
+               if (!gdConfirmWin("Warning", "File exists: overwrite?"))
+                       return;
+
+       if (((SampleChannel*)ch)->save(fullpath))
+               do_callback();
+       else
+               gdAlert("Unable to save this sample!");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_load_sample() {
+       if (browser->text(browser->value()) == NULL)
+               return;
+
+       int res = glue_loadChannel((SampleChannel*) ch, browser->get_selected_item());
+
+       if (res == SAMPLE_LOADED_OK) {
+               do_callback();
+               mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open
+       }
+       else
+               mainWin->keyboard->printChannelMessage(res);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_down() {
+       const char *path = browser->get_selected_item();
+       if (!path)  // when click on an empty area
+               return;
+       if (!gIsDir(path)) {
+
+               /* set the name of the patch/sample/project as the selected item */
+
+               if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) {
+                       if (gIsProject(path)) {
+                               std::string tmp = browser->text(browser->value());
+                               tmp.erase(0, 4);
+                               name->value(tmp.c_str());
+                       }
+                       else
+                               name->value(browser->text(browser->value()));
+               }
+               return;
+       }
+       browser->clear();
+       browser->down_dir(path);
+       browser->sort();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_up() {
+       browser->clear();
+       browser->up_dir();
+       browser->sort();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_save_patch() {
+
+       if (strcmp(name->value(), "") == 0) {  /// FIXME glue business
+               gdAlert("Please choose a file name.");
+               return;
+       }
+
+       /* if name->value() contains ".gptc" */
+
+       char ext[6] = ".gptc";
+       if (strstr(name->value(), ".gptc") != NULL)
+               ext[0] = '\0';
+
+       char fullpath[PATH_MAX];
+       sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext);
+       if (gFileExists(fullpath))
+               if (!gdConfirmWin("Warning", "File exists: overwrite?"))
+                       return;
+
+       if (glue_savePatch(fullpath, name->value(), false)) // false == not a project
+               do_callback();
+       else
+               gdAlert("Unable to save the patch!");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_save_project() {
+
+       if (strcmp(name->value(), "") == 0) {    /// FIXME glue business
+               gdAlert("Please choose a project name.");
+               return;
+       }
+
+       /* check if name->value() contains ".gprj" */
+
+       char ext[6] = ".gprj";
+       if (strstr(name->value(), ".gprj") != NULL)
+               ext[0] = '\0';
+
+       char fullpath[PATH_MAX];
+#if defined(_WIN32)
+       sprintf(fullpath, "%s\\%s%s", where->value(), name->value(), ext);
+#else
+       sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext);
+#endif
+
+       if (gIsProject(fullpath) && !gdConfirmWin("Warning", "Project exists: overwrite?"))
+               return;
+
+       if (glue_saveProject(fullpath, name->value()))
+               do_callback();
+       else
+               gdAlert("Unable to save the project!");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+void gdBrowser::__cb_loadPlugin() {
+
+       if (browser->text(browser->value()) == NULL)
+               return;
+
+       int res = G_PluginHost.addPlugin(browser->get_selected_item(), stackType, ch);
+
+       /* store the folder path inside G_Conf, in order to reuse it the
+        * next time. */
+
+       G_Conf.setPath(G_Conf.pluginPath, where->value());
+
+       if (res)
+               do_callback();
+       else
+               gdAlert("Unable to load the selected plugin!");
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowser::__cb_close() {
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_browser.h b/src/gui/dialogs/gd_browser.h
new file mode 100644 (file)
index 0000000..51bd0c5
--- /dev/null
@@ -0,0 +1,102 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_browser
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_BROWSER_H
+#define GD_BROWSER_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include "../elems/ge_window.h"
+
+
+/* TODO - this class must be subclassed into gdPluginBrowser, gdFileBrowser,
+ * and so on. It's a real mess right now. */
+
+class gdBrowser : public gWindow {
+
+private:
+       static void cb_down(Fl_Widget *v, void *p);
+       static void cb_up  (Fl_Widget *v, void *p);
+       static void cb_load_sample (Fl_Widget *v, void *p);
+       static void cb_save_sample (Fl_Widget *v, void *p);
+       static void cb_load_patch  (Fl_Widget *v, void *p);
+       static void cb_save_patch  (Fl_Widget *v, void *p);
+       static void cb_save_project(Fl_Widget *v, void *p);
+       static void cb_close       (Fl_Widget *w, void *p);
+#ifdef WITH_VST
+       static void cb_loadPlugin  (Fl_Widget *v, void *p);
+#endif
+
+       inline void __cb_down();
+       inline void __cb_up();
+       inline void __cb_load_sample();
+       inline void __cb_save_sample();
+       inline void __cb_save_project();
+       inline void __cb_load_patch();
+       inline void __cb_save_patch();
+       inline void __cb_close();
+#ifdef WITH_VST
+       inline void __cb_loadPlugin();
+#endif
+
+       class gBrowser  *browser;
+       class gClick    *ok;
+       class gClick    *cancel;
+       class gInput    *where;
+       class gInput    *name;
+       class gClick    *updir;
+       class gProgress *status;
+
+       class Channel *ch;
+
+       /* browser type: see const.h */
+
+       /** FIXME internal enum:
+        * enum browserType {
+                * TYPE_A,
+                * TYPE_B,
+                * ....
+                * }; */
+       int type;
+
+       /* PluginHost stack type. Used only when loading plugins */
+
+       int stackType;
+
+       char selectedFile[FILENAME_MAX];
+
+public:
+       gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0);
+       ~gdBrowser();
+
+       char* SelectedFile();
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp
new file mode 100644 (file)
index 0000000..45f8b15
--- /dev/null
@@ -0,0 +1,863 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_config
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/conf.h"
+#include "../../core/midiMapConf.h"
+#include "../../core/patch.h"
+#include "../../core/kernelAudio.h"
+#include "../../core/kernelMidi.h"
+#include "../../utils/gui_utils.h"
+#include "../../utils/log.h"
+#include "../elems/ge_mixed.h"
+#include "gd_config.h"
+#include "gd_keyGrabber.h"
+#include "gd_devInfo.h"
+#include "gd_browser.h"
+
+
+extern Patch G_Patch;
+extern Conf     G_Conf;
+extern bool  G_audio_status;
+extern MidiMapConf G_MidiMap;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gTabMisc::gTabMisc(int X, int Y, int W, int H)
+       : Fl_Group(X, Y, W, H, "Misc")
+{
+       begin();
+       debugMsg = new gChoice(x()+92,  y()+9,  253, 20, "Debug messages");
+       end();
+
+       debugMsg->add("(disabled)");
+       debugMsg->add("To standard output");
+       debugMsg->add("To file");
+
+       labelsize(11);
+
+       switch (G_Conf.logMode) {
+               case LOG_MODE_MUTE:
+                       debugMsg->value(0);
+                       break;
+               case LOG_MODE_STDOUT:
+                       debugMsg->value(1);
+                       break;
+               case LOG_MODE_FILE:
+                       debugMsg->value(2);
+                       break;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMisc::save()
+{
+       switch(debugMsg->value()) {
+               case 0:
+                       G_Conf.logMode = LOG_MODE_MUTE;
+                       break;
+               case 1:
+                       G_Conf.logMode = LOG_MODE_STDOUT;
+                       break;
+               case 2:
+                       G_Conf.logMode = LOG_MODE_FILE;
+                       break;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gTabAudio::gTabAudio(int X, int Y, int W, int H)
+       : Fl_Group(X, Y, W, H, "Sound System")
+{
+       begin();
+       soundsys    = new gChoice(x()+92,  y()+9,  253, 20, "System");
+       buffersize  = new gChoice(x()+92,  y()+37, 55,  20, "Buffer size");
+       samplerate  = new gChoice(x()+290, y()+37, 55,  20, "Sample rate");
+       sounddevOut = new gChoice(x()+92,  y()+65, 225, 20, "Output device");
+       devOutInfo  = new gClick (x()+325, y()+65, 20,  20, "?");
+       channelsOut = new gChoice(x()+92,  y()+93, 55,  20, "Output channels");
+       limitOutput = new gCheck (x()+155, y()+97, 55,  20, "Limit output");
+       sounddevIn  = new gChoice(x()+92,  y()+121, 225, 20, "Input device");
+       devInInfo   = new gClick (x()+325, y()+121, 20,  20, "?");
+       channelsIn  = new gChoice(x()+92,  y()+149, 55,  20, "Input channels");
+       delayComp   = new gInput (x()+290, y()+149, 55,  20, "Rec delay comp.");
+       rsmpQuality = new gChoice(x()+92, y()+177, 253, 20, "Resampling");
+                new gBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92, "Restart Giada for the changes to take effect.");
+       end();
+       labelsize(11);
+
+#if defined(__linux__)
+
+       if (kernelAudio::hasAPI(RtAudio::LINUX_ALSA))
+               soundsys->add("ALSA");
+       if (kernelAudio::hasAPI(RtAudio::UNIX_JACK))
+               soundsys->add("Jack");
+       if (kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
+               soundsys->add("PulseAudio");
+
+       switch (G_Conf.soundSystem) {
+               case SYS_API_ALSA:
+                       soundsys->show("ALSA");
+                       break;
+               case SYS_API_JACK:
+                       soundsys->show("Jack");
+                       buffersize->deactivate();
+                       samplerate->deactivate();
+                       break;
+               case SYS_API_PULSE:
+                       soundsys->show("PulseAudio");
+                       break;
+       }
+       soundsysInitValue = soundsys->value();
+
+#elif defined(_WIN32)
+
+       if (kernelAudio::hasAPI(RtAudio::WINDOWS_DS))
+               soundsys->add("DirectSound");
+       if (kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO))
+               soundsys->add("ASIO");
+       soundsys->show(G_Conf.soundSystem == SYS_API_DS ? "DirectSound" : "ASIO");
+       soundsysInitValue = soundsys->value();
+
+#elif defined (__APPLE__)
+
+       if (kernelAudio::hasAPI(RtAudio::MACOSX_CORE))
+               soundsys->add("CoreAudio");
+       soundsys->show("CoreAudio");
+       soundsysInitValue = soundsys->value();
+
+#endif
+
+       sounddevIn->callback(cb_fetchInChans, this);
+       sounddevOut->callback(cb_fetchOutChans, this);
+
+       devOutInfo->callback(cb_showOutputInfo, this);
+       devInInfo->callback(cb_showInputInfo, this);
+
+       fetchSoundDevs();
+
+       fetchOutChans(sounddevOut->value());
+       fetchInChans(sounddevIn->value());
+
+       buffersize->add("8");
+       buffersize->add("16");
+       buffersize->add("32");
+       buffersize->add("64");
+       buffersize->add("128");
+       buffersize->add("256");
+       buffersize->add("512");
+       buffersize->add("1024");
+       buffersize->add("2048");
+       buffersize->add("4096");
+
+       char buf[8];
+       sprintf(buf, "%d", G_Conf.buffersize);
+       buffersize->show(buf);
+
+       /* fill frequency dropdown menu */
+
+       int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value());
+       for (int i=0; i<nfreq; i++) {
+               char buf[16];
+               int  freq = kernelAudio::getFreq(sounddevOut->value(), i);
+               sprintf(buf, "%d", freq);
+               samplerate->add(buf);
+               if (freq == G_Conf.samplerate)
+                       samplerate->value(i);
+       }
+
+       rsmpQuality->add("Sinc best quality (very slow)");
+       rsmpQuality->add("Sinc medium quality (slow)");
+       rsmpQuality->add("Sinc basic quality (medium)");
+       rsmpQuality->add("Zero Order Hold (fast)");
+       rsmpQuality->add("Linear (very fast)");
+       rsmpQuality->value(G_Conf.rsmpQuality);
+
+       buf[0] = '\0';
+       sprintf(buf, "%d", G_Conf.delayComp);
+       delayComp->value(buf);
+       delayComp->type(FL_INT_INPUT);
+       delayComp->maximum_size(5);
+
+       limitOutput->value(G_Conf.limitOutput);
+       soundsys->callback(cb_deactivate_sounddev, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_deactivate_sounddev(); }
+void gTabAudio::cb_fetchInChans(Fl_Widget *w, void *p)        { ((gTabAudio*)p)->__cb_fetchInChans(); }
+void gTabAudio::cb_fetchOutChans(Fl_Widget *w, void *p)       { ((gTabAudio*)p)->__cb_fetchOutChans(); }
+void gTabAudio::cb_showInputInfo(Fl_Widget *w, void *p)       { ((gTabAudio*)p)->__cb_showInputInfo(); }
+void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p)      { ((gTabAudio*)p)->__cb_showOutputInfo(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::__cb_fetchInChans()
+{
+       fetchInChans(sounddevIn->value());
+       channelsIn->value(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::__cb_fetchOutChans()
+{
+       fetchOutChans(sounddevOut->value());
+       channelsOut->value(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::__cb_showInputInfo()
+{
+       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       new gdDevInfo(dev);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::__cb_showOutputInfo()
+{
+       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       new gdDevInfo(dev);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::__cb_deactivate_sounddev()
+{
+       /* if the user changes sound system (eg ALSA->JACK) device menu deactivates.
+        * If it returns to the original sound system, we re-fill the list by
+        * querying kernelAudio. */
+
+       if (soundsysInitValue == soundsys->value()) {
+               sounddevOut->clear();
+               sounddevIn->clear();
+
+               fetchSoundDevs();
+
+               /* the '?' button is added by fetchSoundDevs */
+
+               fetchOutChans(sounddevOut->value());
+               sounddevOut->activate();
+               channelsOut->activate();
+
+               /* chan menus and '?' button are activated by fetchInChans(...) */
+
+               fetchInChans(sounddevIn->value());
+               sounddevIn->activate();
+       }
+       else {
+               sounddevOut->deactivate();
+               sounddevOut->clear();
+               sounddevOut->add("-- restart to fetch device(s) --");
+               sounddevOut->value(0);
+               channelsOut->deactivate();
+               devOutInfo->deactivate();
+
+               sounddevIn->deactivate();
+               sounddevIn->clear();
+               sounddevIn->add("-- restart to fetch device(s) --");
+               sounddevIn->value(0);
+               channelsIn->deactivate();
+               devInInfo->deactivate();
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::fetchInChans(int menuItem)
+{
+       /* if menuItem==0 device in input is disabled. */
+
+       if (menuItem == 0) {
+               devInInfo ->deactivate();
+               channelsIn->deactivate();
+               delayComp ->deactivate();
+               return;
+       }
+
+       devInInfo ->activate();
+       channelsIn->activate();
+       delayComp ->activate();
+
+       channelsIn->clear();
+
+       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       unsigned chs = kernelAudio::getMaxInChans(dev);
+
+       if (chs == 0) {
+               channelsIn->add("none");
+               channelsIn->value(0);
+               return;
+       }
+       for (unsigned i=0; i<chs; i+=2) {
+               char str[16];
+               sprintf(str, "%d-%d", (i+1), (i+2));
+               channelsIn->add(str);
+       }
+       channelsIn->value(G_Conf.channelsIn);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::fetchOutChans(int menuItem)
+{
+       channelsOut->clear();
+
+       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       unsigned chs = kernelAudio::getMaxOutChans(dev);
+
+       if (chs == 0) {
+               channelsOut->add("none");
+               channelsOut->value(0);
+               return;
+       }
+       for (unsigned i=0; i<chs; i+=2) {
+               char str[16];
+               sprintf(str, "%d-%d", (i+1), (i+2));
+               channelsOut->add(str);
+       }
+       channelsOut->value(G_Conf.channelsOut);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gTabAudio::findMenuDevice(gChoice *m, int device)
+{
+       if (device == -1)
+               return 0;
+
+       if (G_audio_status == false)
+               return 0;
+
+       for (int i=0; i<m->size(); i++) {
+               if (kernelAudio::getDeviceName(device) == NULL)
+                       continue;
+               if (m->text(i) == NULL)
+                       continue;
+               if (strcmp(m->text(i), kernelAudio::getDeviceName(device))==0)
+                       return i;
+       }
+
+       return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::fetchSoundDevs()
+{
+       if (kernelAudio::numDevs == 0) {
+               sounddevOut->add("-- no devices found --");
+               sounddevOut->value(0);
+               sounddevIn->add("-- no devices found --");
+               sounddevIn->value(0);
+               devInInfo ->deactivate();
+               devOutInfo->deactivate();
+       }
+       else {
+
+               devInInfo ->activate();
+               devOutInfo->activate();
+
+               /* input device may be disabled: now device number -1 is the disabled
+                * one. KernelAudio knows how to handle it. */
+
+               sounddevIn->add("(disabled)");
+
+               for (unsigned i=0; i<kernelAudio::numDevs; i++) {
+
+                       /* escaping '/', very dangerous in FLTK (it creates a submenu) */
+
+                       std::string tmp = kernelAudio::getDeviceName(i);
+                       for (unsigned k=0; k<tmp.size(); k++)
+                               if (tmp[k] == '/' || tmp[k] == '|' || tmp[k] == '&' || tmp[k] == '_')
+                                       tmp[k] = '-';
+
+                       /* add to list devices with at least 1 channel available. In this
+                        * way we can filter devices only for input or output, e.g. an input
+                        * devices has 0 output channels. */
+
+                       if (kernelAudio::getMaxOutChans(i) > 0)
+                               sounddevOut->add(tmp.c_str());
+
+                       if (kernelAudio::getMaxInChans(i) > 0)
+                               sounddevIn->add(tmp.c_str());
+               }
+
+               /* we show the device saved in the configuration file. */
+
+               if (sounddevOut->size() == 0) {
+                       sounddevOut->add("-- no devices found --");
+                       sounddevOut->value(0);
+                       devOutInfo->deactivate();
+               }
+               else {
+                       int outMenuValue = findMenuDevice(sounddevOut, G_Conf.soundDeviceOut);
+                       sounddevOut->value(outMenuValue);
+               }
+
+               if (sounddevIn->size() == 0) {
+                       sounddevIn->add("-- no devices found --");
+                       sounddevIn->value(0);
+                       devInInfo->deactivate();
+               }
+               else {
+                       int inMenuValue = findMenuDevice(sounddevIn, G_Conf.soundDeviceIn);
+                       sounddevIn->value(inMenuValue);
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabAudio::save()
+{
+       /** FIXME - wrong, if API is missing! Right way in gTabMidi::save */
+
+#ifdef __linux__
+       if      (soundsys->value() == 0)        G_Conf.soundSystem = SYS_API_ALSA;
+       else if (soundsys->value() == 1)        G_Conf.soundSystem = SYS_API_JACK;
+       else if (soundsys->value() == 2)        G_Conf.soundSystem = SYS_API_PULSE;
+#else
+#ifdef _WIN32
+       if                      (soundsys->value() == 0)        G_Conf.soundSystem = SYS_API_DS;
+       else if (soundsys->value() == 1)  G_Conf.soundSystem = SYS_API_ASIO;
+#endif
+#endif
+
+       /* use the device name to search into the drop down menu's */
+
+       G_Conf.soundDeviceOut = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       G_Conf.soundDeviceIn  = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       G_Conf.channelsOut    = channelsOut->value();
+       G_Conf.channelsIn     = channelsIn->value();
+       G_Conf.limitOutput    = limitOutput->value();
+       G_Conf.rsmpQuality    = rsmpQuality->value();
+
+       /* if sounddevOut is disabled (because of system change e.g. alsa ->
+        * jack) its value is equal to -1. Change it! */
+
+       if (G_Conf.soundDeviceOut == -1)
+               G_Conf.soundDeviceOut = 0;
+
+       int bufsize = atoi(buffersize->text());
+       if (bufsize % 2 != 0) bufsize++;
+       if (bufsize < 8)                  bufsize = 8;
+       if (bufsize > 8192)             bufsize = 8192;
+       G_Conf.buffersize = bufsize;
+
+       const Fl_Menu_Item *i = NULL;
+       i = samplerate->mvalue(); // mvalue() returns a pointer to the last menu item that was picked
+       if (i)
+               G_Conf.samplerate = atoi(i->label());
+
+       int _delayComp = atoi(delayComp->value());
+       if (_delayComp < 0) _delayComp = 0;
+       G_Conf.delayComp = _delayComp;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gTabMidi::gTabMidi(int X, int Y, int W, int H)
+       : Fl_Group(X, Y, W, H, "MIDI")
+{
+       begin();
+       system    = new gChoice(x()+92, y()+9, 253, 20, "System");
+       portOut   = new gChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port");
+       portIn    = new gChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port");
+       noNoteOff = new gCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff");
+       midiMap   = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map");
+       sync        = new gChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync");
+       new gBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect.");
+       end();
+
+       labelsize(11);
+
+       system->callback(cb_changeSystem, (void*)this);
+
+       fetchSystems();
+       fetchOutPorts();
+       fetchInPorts();
+       fetchMidiMaps();
+
+       noNoteOff->value(G_Conf.noNoteOff);
+
+       sync->add("(disabled)");
+       sync->add("MIDI Clock (master)");
+       sync->add("MTC (master)");
+       if      (G_Conf.midiSync == MIDI_SYNC_NONE)
+               sync->value(0);
+       else if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
+               sync->value(1);
+       else if (G_Conf.midiSync == MIDI_SYNC_MTC_M)
+               sync->value(2);
+
+       systemInitValue = system->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::fetchOutPorts() {
+
+       if (kernelMidi::numOutPorts == 0) {
+               portOut->add("-- no ports found --");
+               portOut->value(0);
+               portOut->deactivate();
+       }
+       else {
+
+               portOut->add("(disabled)");
+
+               for (unsigned i=0; i<kernelMidi::numOutPorts; i++) {
+                       char *t = (char*) kernelMidi::getOutPortName(i);
+                       for (int k=0; t[k] != '\0'; k++)
+                               if (t[k] == '/' || t[k] == '|' || t[k] == '&' || t[k] == '_')
+                                       t[k] = '-';
+                       portOut->add(t);
+               }
+
+               portOut->value(G_Conf.midiPortOut+1);    // +1 because midiPortOut=-1 is '(disabled)'
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::fetchInPorts()
+{
+       if (kernelMidi::numInPorts == 0) {
+               portIn->add("-- no ports found --");
+               portIn->value(0);
+               portIn->deactivate();
+       }
+       else {
+
+               portIn->add("(disabled)");
+
+               for (unsigned i=0; i<kernelMidi::numInPorts; i++) {
+                       char *t = (char*) kernelMidi::getInPortName(i);
+                       for (int k=0; t[k] != '\0'; k++)
+                               if (t[k] == '/' || t[k] == '|' || t[k] == '&' || t[k] == '_')
+                                       t[k] = '-';
+                       portIn->add(t);
+               }
+
+               portIn->value(G_Conf.midiPortIn+1);    // +1 because midiPortIn=-1 is '(disabled)'
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::fetchMidiMaps()
+{
+       if (G_MidiMap.maps.size == 0) {
+               midiMap->add("(no MIDI maps available)");
+               midiMap->value(0);
+               midiMap->deactivate();
+               return;
+       }
+       for (unsigned i=0; i<G_MidiMap.maps.size; i++) {
+               const char *imap = G_MidiMap.maps.at(i).c_str();
+               midiMap->add(imap);
+               if (strcmp(G_Conf.midiMapPath, imap) == 0)
+                       midiMap->value(i);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::save()
+{
+       if      (!strcmp("ALSA", system->text(system->value())))
+               G_Conf.midiSystem = RtMidi::LINUX_ALSA;
+       else if (!strcmp("Jack", system->text(system->value())))
+               G_Conf.midiSystem = RtMidi::UNIX_JACK;
+       else if (!strcmp("Multimedia MIDI", system->text(system->value())))
+               G_Conf.midiSystem = RtMidi::WINDOWS_MM;
+       else if (!strcmp("OSX Core MIDI", system->text(system->value())))
+               G_Conf.midiSystem = RtMidi::MACOSX_CORE;
+
+       G_Conf.midiPortOut = portOut->value()-1;   // -1 because midiPortOut=-1 is '(disabled)'
+       G_Conf.midiPortIn  = portIn->value()-1;    // -1 because midiPortIn=-1 is '(disabled)'
+
+       G_Conf.noNoteOff   = noNoteOff->value();
+
+       G_Conf.setPath(G_Conf.midiMapPath, midiMap->text(midiMap->value()));
+
+       if      (sync->value() == 0)
+               G_Conf.midiSync = MIDI_SYNC_NONE;
+       else if (sync->value() == 1)
+               G_Conf.midiSync = MIDI_SYNC_CLOCK_M;
+       else if (sync->value() == 2)
+               G_Conf.midiSync = MIDI_SYNC_MTC_M;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::fetchSystems()
+{
+#if defined(__linux__)
+
+       if (kernelMidi::hasAPI(RtMidi::LINUX_ALSA))
+               system->add("ALSA");
+       if (kernelMidi::hasAPI(RtMidi::UNIX_JACK))
+               system->add("Jack");
+
+#elif defined(_WIN32)
+
+       if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM))
+               system->add("Multimedia MIDI");
+
+#elif defined (__APPLE__)
+
+       system->add("OSX Core MIDI");
+
+#endif
+
+       switch (G_Conf.midiSystem) {
+               case RtMidi::LINUX_ALSA:  system->show("ALSA"); break;
+               case RtMidi::UNIX_JACK:   system->show("Jack"); break;
+               case RtMidi::WINDOWS_MM:  system->show("Multimedia MIDI"); break;
+               case RtMidi::MACOSX_CORE: system->show("OSX Core MIDI"); break;
+               default: system->value(0); break;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((gTabMidi*)p)->__cb_changeSystem(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::__cb_changeSystem()
+{
+       /* if the user changes MIDI device (eg ALSA->JACK) device menu deactivates.
+        * If it returns to the original system, we re-fill the list by
+        * querying kernelMidi. */
+
+       if (systemInitValue == system->value()) {
+               portOut->clear();
+               fetchOutPorts();
+               portOut->activate();
+       }
+       else {
+               portOut->deactivate();
+               portOut->clear();
+               portOut->add("-- restart to fetch device(s) --");
+               portOut->value(0);
+       }
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H)
+       : Fl_Group(X, Y, W, H, "Behaviors")
+{
+       begin();
+       Fl_Group *radioGrp_1 = new Fl_Group(x(), y()+10, w(), 70); // radio group for the mutex
+               new gBox(x(), y()+10, 70, 25, "When a channel with recorded actions is halted:", FL_ALIGN_LEFT);
+               recsStopOnChanHalt_1 = new gRadio(x()+25, y()+35, 280, 20, "stop it immediately");
+               recsStopOnChanHalt_0 = new gRadio(x()+25, y()+55, 280, 20, "play it until finished");
+       radioGrp_1->end();
+
+       Fl_Group *radioGrp_2 = new Fl_Group(x(), y()+70, w(), 70); // radio group for the mutex
+               new gBox(x(), y()+80, 70, 25, "When the sequencer is halted:", FL_ALIGN_LEFT);
+               chansStopOnSeqHalt_1 = new gRadio(x()+25, y()+105, 280, 20, "stop immediately all dynamic channels");
+               chansStopOnSeqHalt_0 = new gRadio(x()+25, y()+125, 280, 20, "play all dynamic channels until finished");
+       radioGrp_2->end();
+
+       treatRecsAsLoops  = new gCheck(x(), y()+155, 280, 20, "Treat one shot channels with actions as loops");
+
+       end();
+       labelsize(11);
+
+       G_Conf.recsStopOnChanHalt == 1 ? recsStopOnChanHalt_1->value(1) : recsStopOnChanHalt_0->value(1);
+       G_Conf.chansStopOnSeqHalt == 1 ? chansStopOnSeqHalt_1->value(1) : chansStopOnSeqHalt_0->value(1);
+       G_Conf.treatRecsAsLoops   == 1 ? treatRecsAsLoops->value(1)  : treatRecsAsLoops->value(0);
+
+       recsStopOnChanHalt_1->callback(cb_radio_mutex, (void*)this);
+       recsStopOnChanHalt_0->callback(cb_radio_mutex, (void*)this);
+       chansStopOnSeqHalt_1->callback(cb_radio_mutex, (void*)this);
+       chansStopOnSeqHalt_0->callback(cb_radio_mutex, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabBehaviors::cb_radio_mutex(Fl_Widget *w, void *p) { ((gTabBehaviors*)p)->__cb_radio_mutex(w); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w)
+{
+       ((Fl_Button *)w)->type(FL_RADIO_BUTTON);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gTabBehaviors::save()
+{
+       G_Conf.recsStopOnChanHalt = recsStopOnChanHalt_1->value() == 1 ? 1 : 0;
+       G_Conf.chansStopOnSeqHalt = chansStopOnSeqHalt_1->value() == 1 ? 1 : 0;
+       G_Conf.treatRecsAsLoops   = treatRecsAsLoops->value() == 1 ? 1 : 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration")
+{
+       set_modal();
+
+       if (G_Conf.configX)
+               resize(G_Conf.configX, G_Conf.configY, this->w(), this->h());
+
+       Fl_Tabs *tabs = new Fl_Tabs(8, 8, w-16, h-44);
+               tabAudio     = new gTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+               tabMidi      = new gTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+               tabBehaviors = new gTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+               tabMisc      = new gTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+       tabs->end();
+
+       save     = new gClick (w-88, h-28, 80, 20, "Save");
+       cancel = new gClick (w-176, h-28, 80, 20, "Cancel");
+
+       end();
+
+       tabs->box(FL_FLAT_BOX); // TODO - G_BOX crashes FLTK 1.3.3
+
+       tabs->labelcolor(COLOR_TEXT_0);
+
+       save->callback(cb_save_config, (void*)this);
+       cancel->callback(cb_cancel, (void*)this);
+
+       gu_setFavicon(this);
+       setId(WID_CONFIG);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdConfig::~gdConfig()
+{
+       G_Conf.configX = x();
+       G_Conf.configY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::cb_save_config(Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_save_config(); }
+void gdConfig::cb_cancel     (Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_cancel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::__cb_save_config()
+{
+       tabAudio->save();
+       tabBehaviors->save();
+       tabMidi->save();
+       tabMisc->save();
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::__cb_cancel()
+{
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_config.h b/src/gui/dialogs/gd_config.h
new file mode 100644 (file)
index 0000000..64d06d4
--- /dev/null
@@ -0,0 +1,171 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_config
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GD_CONFIG_H
+#define GD_CONFIG_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Tabs.H>
+#include "../elems/ge_window.h"
+
+
+class gdConfig : public gWindow
+{
+private:
+       static void cb_save_config        (Fl_Widget *w, void *p);
+       static void cb_cancel             (Fl_Widget *w, void *p);
+       inline void __cb_save_config();
+       inline void __cb_cancel();
+
+public:
+       gdConfig(int w, int h);
+       ~gdConfig();
+
+       class gTabAudio     *tabAudio;
+       class gTabBehaviors *tabBehaviors;
+       class gTabMidi      *tabMidi;
+       class gTabMisc      *tabMisc;
+       class gClick          *save;
+       class gClick          *cancel;
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gTabMidi : public Fl_Group
+{
+private:
+
+       void fetchSystems();
+       void fetchOutPorts();
+       void fetchInPorts();
+       void fetchMidiMaps();
+
+       static void cb_changeSystem  (Fl_Widget *w, void *p);
+       inline void __cb_changeSystem();
+
+       int systemInitValue;
+
+public:
+       
+       class gChoice *system;
+       class gChoice *portOut;
+       class gChoice *portIn;
+       class gCheck  *noNoteOff;
+       class gChoice *midiMap;
+       class gChoice *sync;
+
+       gTabMidi(int x, int y, int w, int h);
+
+       void save();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gTabAudio : public Fl_Group
+{
+private:
+       static void cb_deactivate_sounddev(Fl_Widget *w, void *p);
+       static void cb_fetchInChans       (Fl_Widget *w, void *p);
+       static void cb_fetchOutChans      (Fl_Widget *w, void *p);
+       static void cb_showInputInfo      (Fl_Widget *w, void *p);
+       static void cb_showOutputInfo     (Fl_Widget *w, void *p);
+       inline void __cb_deactivate_sounddev();
+       inline void __cb_fetchInChans();
+       inline void __cb_fetchOutChans();
+       inline void __cb_showInputInfo();
+       inline void __cb_showOutputInfo();
+
+       void fetchSoundDevs();
+       void fetchInChans(int menuItem);
+       void fetchOutChans(int menuItem);
+       int  findMenuDevice(class gChoice *m, int device);
+
+       int soundsysInitValue;
+
+public:
+       class gChoice *soundsys;
+       class gChoice *samplerate;
+       class gChoice *rsmpQuality;
+       class gChoice *sounddevIn;
+       class gClick  *devInInfo;
+       class gChoice *channelsIn;
+       class gChoice *sounddevOut;
+       class gClick  *devOutInfo;
+       class gChoice *channelsOut;
+       class gCheck  *limitOutput;
+       class gChoice *buffersize;
+       class gInput  *delayComp;
+
+       gTabAudio(int x, int y, int w, int h);
+
+       void save();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gTabBehaviors : public Fl_Group
+{
+private:
+       static void cb_radio_mutex  (Fl_Widget *w, void *p);
+       inline void __cb_radio_mutex(Fl_Widget *w);
+
+public:
+       class gRadio *recsStopOnChanHalt_1;
+       class gRadio *recsStopOnChanHalt_0;
+       class gRadio *chansStopOnSeqHalt_1;
+       class gRadio *chansStopOnSeqHalt_0;
+       class gCheck *treatRecsAsLoops;
+
+       gTabBehaviors(int x, int y, int w, int h);
+
+       void save();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gTabMisc : public Fl_Group
+{
+public:
+       class gChoice *debugMsg;
+
+       gTabMisc(int x, int y, int w, int h);
+
+       void save();
+};
+
+
+#endif
diff --git a/src/gui/dialogs/gd_devInfo.cpp b/src/gui/dialogs/gd_devInfo.cpp
new file mode 100644 (file)
index 0000000..efdc064
--- /dev/null
@@ -0,0 +1,107 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_devInfo
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../core/kernelAudio.h"
+#include "../../utils/gui_utils.h"
+#include "../elems/ge_mixed.h"
+#include "gd_devInfo.h"
+
+
+gdDevInfo::gdDevInfo(unsigned dev)
+: Fl_Window(340, 300, "Device information") {
+       set_modal();
+
+       text  = new gBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+       close = new gClick(252, h()-28, 80, 20, "Close");
+       end();
+
+       std::string bufTxt;
+       char bufNum[128];
+       int  lines = 0;
+
+       bufTxt  = "Device name: ";
+       bufTxt += +kernelAudio::getDeviceName(dev);
+       bufTxt += "\n";
+       lines++;
+
+       bufTxt += "Total output(s): ";
+       sprintf(bufNum, "%d\n", kernelAudio::getMaxOutChans(dev));
+       bufTxt += bufNum;
+       lines++;
+
+       bufTxt += "Total intput(s): ";
+       sprintf(bufNum, "%d\n", kernelAudio::getMaxInChans(dev));
+       bufTxt += bufNum;
+       lines++;
+
+       bufTxt += "Duplex channel(s): ";
+       sprintf(bufNum, "%d\n", kernelAudio::getDuplexChans(dev));
+       bufTxt += bufNum;
+       lines++;
+
+       bufTxt += "Default output: ";
+       sprintf(bufNum, "%s\n", kernelAudio::isDefaultOut(dev) ? "yes" : "no");
+       bufTxt += bufNum;
+       lines++;
+
+       bufTxt += "Default input: ";
+       sprintf(bufNum, "%s\n", kernelAudio::isDefaultIn(dev) ? "yes" : "no");
+       bufTxt += bufNum;
+       lines++;
+
+       int totalFreq = kernelAudio::getTotalFreqs(dev);
+       bufTxt += "Supported frequencies: ";
+       sprintf(bufNum, "%d", totalFreq);
+       bufTxt += bufNum;
+       lines++;
+
+       for (int i=0; i<totalFreq; i++) {
+               sprintf(bufNum, "%d  ", kernelAudio::getFreq(dev, i));
+               if (i%6 == 0) {    // new line each X printed freqs AND on the first line (i%0 != 0)
+                       bufTxt += "\n    ";
+                       lines++;
+               }
+               bufTxt += bufNum;
+       }
+
+       text->copy_label(bufTxt.c_str());
+
+       /* resize the window to fit the content. fl_height() returns the height
+        * of a line. fl_height() * total lines + margins + button size */
+
+       resize(x(), y(), w(), lines*fl_height() + 8 + 8 + 8 + 20);
+       close->position(close->x(), lines*fl_height() + 8 + 8);
+
+       close->callback(__cb_window_closer, (void*)this);
+       gu_setFavicon(this);
+       show();
+}
+
+
+gdDevInfo::~gdDevInfo() {}
diff --git a/src/gui/dialogs/gd_devInfo.h b/src/gui/dialogs/gd_devInfo.h
new file mode 100644 (file)
index 0000000..c5a06ca
--- /dev/null
@@ -0,0 +1,47 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_devInfo
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_DEV_INFO_H
+#define GD_DEV_INFO_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+
+
+class gdDevInfo : public Fl_Window {
+private:
+       class gBox       *text;
+       class gClick *close;
+
+public:
+       gdDevInfo(unsigned dev);
+       ~gdDevInfo();
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_editor.cpp b/src/gui/dialogs/gd_editor.cpp
new file mode 100644 (file)
index 0000000..231bdec
--- /dev/null
@@ -0,0 +1,491 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_editor
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../utils/gui_utils.h"
+#include "../../glue/glue.h"
+#include "../../core/waveFx.h"
+#include "../../core/conf.h"
+#include "../../core/graphics.h"
+#include "../../core/mixerHandler.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/mixer.h"
+#include "../../core/wave.h"
+#include "../elems/ge_waveform.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_channel.h"
+#include "../elems/ge_waveTools.h"
+#include "../elems/ge_keyboard.h"
+#include "gd_editor.h"
+#include "gd_mainWindow.h"
+#include "gd_warnings.h"
+
+
+extern Mixer         G_Mixer;
+extern gdMainWindow *mainWin;
+extern Conf          G_Conf;
+
+
+gdEditor::gdEditor(SampleChannel *ch)
+  : gWindow(640, 480),
+    ch(ch)
+{
+  set_non_modal();
+
+  if (G_Conf.sampleEditorX)
+    resize(G_Conf.sampleEditorX, G_Conf.sampleEditorY, G_Conf.sampleEditorW, G_Conf.sampleEditorH);
+
+  /* top bar: grid and zoom tools */
+
+  Fl_Group *bar = new Fl_Group(8, 8, w()-16, 20);
+  bar->begin();
+    grid    = new gChoice(bar->x(), bar->y(), 50, 20);
+    snap    = new gCheck(grid->x()+grid->w()+4, bar->y()+4, 12, 12);
+    zoomOut = new gClick(bar->x()+bar->w()-20, bar->y(), 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
+    zoomIn  = new gClick(zoomOut->x()-24, bar->y(), 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+  bar->end();
+  bar->resizable(new gBox(grid->x()+grid->w()+4, bar->y(), 80, bar->h()));
+
+  /* waveform */
+
+  waveTools = new gWaveTools(8, 36, w()-16, h()-120, ch);
+  waveTools->end();
+
+  /* other tools */
+
+  Fl_Group *tools = new Fl_Group(8, waveTools->y()+waveTools->h()+8, w()-16, 130);
+  tools->begin();
+    volume        = new gDial (tools->x()+42,                    tools->y(), 20, 20, "Volume");
+    volumeNum     = new gInput(volume->x()+volume->w()+4,        tools->y(), 46, 20, "dB");
+
+    boost         = new gDial (volumeNum->x()+volumeNum->w()+80, tools->y(), 20, 20, "Boost");
+    boostNum      = new gInput(boost->x()+boost->w()+4,          tools->y(), 46, 20, "dB");
+
+    normalize     = new gClick(boostNum->x()+boostNum->w()+54,   tools->y(), 70, 20, "Normalize");
+    pan           = new gDial (normalize->x()+normalize->w()+40, tools->y(), 20, 20, "Pan");
+    panNum        = new gInput(pan->x()+pan->w()+4,              tools->y(), 45, 20, "%");
+
+    pitch         = new gDial (tools->x()+42,                       volume->y()+volume->h()+4, 20, 20, "Pitch");
+    pitchNum      = new gInput(pitch->x()+pitch->w()+4,             volume->y()+volume->h()+4, 46, 20);
+    pitchToBar    = new gClick(pitchNum->x()+pitchNum->w()+4,       volume->y()+volume->h()+4, 46, 20, "To bar");
+    pitchToSong   = new gClick(pitchToBar->x()+pitchToBar->w()+4,   volume->y()+volume->h()+4, 46, 20, "To song");
+    pitchHalf     = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 21, 20, "÷");
+    pitchDouble   = new gClick(pitchHalf->x()+pitchHalf->w()+4,     volume->y()+volume->h()+4, 21, 20, "×");
+    pitchReset    = new gClick(pitchDouble->x()+pitchDouble->w()+4, volume->y()+volume->h()+4, 46, 20, "Reset");
+    reload        = new gClick(pitchReset->x()+pitchReset->w()+4,   volume->y()+volume->h()+4, 70, 20, "Reload");
+
+    chanStart     = new gInput(tools->x()+52,                    pitch->y()+pitch->h()+4, 60, 20, "Start");
+    chanEnd       = new gInput(chanStart->x()+chanStart->w()+40, pitch->y()+pitch->h()+4, 60, 20, "End");
+    resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4,      pitch->y()+pitch->h()+4, 46, 20, "Reset");
+
+  tools->end();
+  tools->resizable(new gBox(panNum->x()+panNum->w()+4, tools->y(), 80, tools->h()));
+
+  /* grid tool setup */
+
+  grid->add("(off)");
+  grid->add("2");
+  grid->add("3");
+  grid->add("4");
+  grid->add("6");
+  grid->add("8");
+  grid->add("16");
+  grid->add("32");
+  grid->add("64");
+  grid->value(G_Conf.sampleEditorGridVal);
+  grid->callback(cb_changeGrid, (void*)this);
+
+  snap->value(G_Conf.sampleEditorGridOn);
+  snap->callback(cb_enableSnap, (void*)this);
+
+  /* TODO - redraw grid if != (off) */
+
+  char buf[16];
+  sprintf(buf, "%d", ch->begin / 2); // divided by 2 because stereo
+  chanStart->value(buf);
+  chanStart->type(FL_INT_INPUT);
+  chanStart->callback(cb_setChanPos, this);
+
+  /* inputs callback: fire when they lose focus or Enter is pressed. */
+
+  chanStart->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
+  chanEnd  ->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
+
+  sprintf(buf, "%d", ch->end / 2);  // divided by 2 because stereo
+  chanEnd->value(buf);
+  chanEnd->type(FL_INT_INPUT);
+  chanEnd->callback(cb_setChanPos, this);
+
+  resetStartEnd->callback(cb_resetStartEnd, this);
+
+  volume->callback(cb_setVolume, (void*)this);
+  volume->value(ch->guiChannel->vol->value());
+
+  float dB = 20*log10(ch->volume);   // dB = 20*log_10(linear value)
+  if (dB > -INFINITY) sprintf(buf, "%.2f", dB);
+  else                sprintf(buf, "-inf");
+  volumeNum->value(buf);
+  volumeNum->align(FL_ALIGN_RIGHT);
+  volumeNum->callback(cb_setVolumeNum, (void*)this);
+
+  boost->range(1.0f, 10.0f);
+  boost->callback(cb_setBoost, (void*)this);
+  if (ch->boost > 10.f)
+    boost->value(10.0f);
+  else
+    boost->value(ch->boost);
+  boost->when(FL_WHEN_CHANGED | FL_WHEN_RELEASE);
+
+  float boost = 20*log10(ch->boost); // dB = 20*log_10(linear value)
+  sprintf(buf, "%.2f", boost);
+  boostNum->value(buf);
+  boostNum->align(FL_ALIGN_RIGHT);
+  boostNum->callback(cb_setBoostNum, (void*)this);
+
+  normalize->callback(cb_normalize, (void*)this);
+
+  pan->range(0.0f, 2.0f);
+  pan->callback(cb_panning, (void*)this);
+
+  pitch->range(0.01f, 4.0f);
+  pitch->value(ch->pitch);
+  pitch->callback(cb_setPitch, (void*)this);
+  pitch->when(FL_WHEN_RELEASE);
+
+  sprintf(buf, "%.4f", ch->pitch); // 4 digits
+  pitchNum->value(buf);
+  pitchNum->align(FL_ALIGN_RIGHT);
+  pitchNum->callback(cb_setPitchNum, (void*)this);
+  pitchNum->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
+
+  pitchToBar->callback(cb_setPitchToBar, (void*)this);
+  pitchToSong->callback(cb_setPitchToSong, (void*)this);
+  pitchHalf->callback(cb_setPitchHalf, (void*)this);
+  pitchDouble->callback(cb_setPitchDouble, (void*)this);
+  pitchReset->callback(cb_resetPitch, (void*)this);
+
+  reload->callback(cb_reload, (void*)this);
+
+  zoomOut->callback(cb_zoomOut, (void*)this);
+  zoomIn->callback(cb_zoomIn, (void*)this);
+
+  /* logical samples (aka takes) cannot be reloaded. So far. */
+
+  if (ch->wave->isLogical)
+    reload->deactivate();
+
+  if (ch->panRight < 1.0f) {
+    char buf[8];
+    sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100));
+    pan->value(ch->panRight);
+    panNum->value(buf);
+  }
+  else if (ch->panRight == 1.0f && ch->panLeft == 1.0f) {
+    pan->value(1.0f);
+    panNum->value("C");
+  }
+  else {
+    char buf[8];
+    sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100));
+    pan->value(2.0f - ch->panLeft);
+    panNum->value(buf);
+  }
+
+  panNum->align(FL_ALIGN_RIGHT);
+  panNum->readonly(1);
+  panNum->cursor_color(FL_WHITE);
+
+  gu_setFavicon(this);
+  size_range(640, 480);
+  resizable(waveTools);
+
+  label(ch->wave->name.c_str());
+
+  show();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdEditor::~gdEditor()
+{
+  G_Conf.sampleEditorX = x();
+  G_Conf.sampleEditorY = y();
+  G_Conf.sampleEditorW = w();
+  G_Conf.sampleEditorH = h();
+  G_Conf.sampleEditorGridVal = grid->value();
+  G_Conf.sampleEditorGridOn  = snap->value();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::cb_setChanPos      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setChanPos(); }
+void gdEditor::cb_resetStartEnd   (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetStartEnd(); }
+void gdEditor::cb_setVolume       (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolume(); }
+void gdEditor::cb_setVolumeNum    (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolumeNum(); }
+void gdEditor::cb_setBoost        (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoost(); }
+void gdEditor::cb_setBoostNum     (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoostNum(); }
+void gdEditor::cb_normalize       (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_normalize(); }
+void gdEditor::cb_panning         (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_panning(); }
+void gdEditor::cb_reload          (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_reload(); }
+void gdEditor::cb_setPitch        (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitch(); }
+void gdEditor::cb_setPitchToBar   (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToBar(); }
+void gdEditor::cb_setPitchToSong  (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToSong(); }
+void gdEditor::cb_setPitchHalf    (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchHalf(); }
+void gdEditor::cb_setPitchDouble  (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchDouble(); }
+void gdEditor::cb_resetPitch      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetPitch(); }
+void gdEditor::cb_setPitchNum     (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchNum(); }
+void gdEditor::cb_zoomIn          (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomIn(); }
+void gdEditor::cb_zoomOut         (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomOut(); }
+void gdEditor::cb_changeGrid      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_changeGrid(); }
+void gdEditor::cb_enableSnap      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_enableSnap(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_enableSnap()
+{
+  waveTools->waveform->setSnap(!waveTools->waveform->getSnap());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitchToBar()
+{
+  glue_setPitch(this, ch, ch->end/(float)G_Mixer.framesPerBar, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitchToSong()
+{
+  glue_setPitch(this, ch, ch->end/(float)G_Mixer.totalFrames, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_resetPitch()
+{
+  glue_setPitch(this, ch, 1.0f, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setChanPos()
+{
+  glue_setBeginEndChannel(
+    this,
+    ch,
+    atoi(chanStart->value())*2,  // glue halves printed values
+    atoi(chanEnd->value())*2,
+    true
+  );
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_resetStartEnd()
+{
+  glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setVolume()
+{
+  glue_setVolEditor(this, ch, volume->value(), false);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setVolumeNum()
+{
+  glue_setVolEditor(this, ch, atof(volumeNum->value()), true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setBoost()
+{
+  if (Fl::event() == FL_DRAG)
+    glue_setBoost(this, ch, boost->value(), false);
+  else if (Fl::event() == FL_RELEASE) {
+    glue_setBoost(this, ch, boost->value(), false);
+  waveTools->updateWaveform();
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setBoostNum()
+{
+  glue_setBoost(this, ch, atof(boostNum->value()), true);
+  waveTools->updateWaveform();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_normalize()
+{
+  float val = wfx_normalizeSoft(ch->wave);
+  glue_setBoost(this, ch, val, false); // we pretend that a fake user turns the dial (numeric=false)
+  if (val < 0.0f)
+    boost->value(0.0f);
+  else
+  if (val > 20.0f) // a dial > than it's max value goes crazy
+    boost->value(10.0f);
+  else
+    boost->value(val);
+  waveTools->updateWaveform();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_panning()
+{
+  glue_setPanning(this, ch, pan->value());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_reload()
+{
+  if (!gdConfirmWin("Warning", "Reload sample: are you sure?"))
+    return;
+
+  /* no need for glue_loadChan, there's no gui to refresh */
+
+  ch->load(ch->wave->pathfile.c_str());
+
+  glue_setBoost(this, ch, DEFAULT_BOOST, true);
+  glue_setPitch(this, ch, gDEFAULT_PITCH, true);
+  glue_setPanning(this, ch, 1.0f);
+  pan->value(1.0f);  // glue_setPanning doesn't do it
+  pan->redraw();     // glue_setPanning doesn't do it
+
+  waveTools->waveform->stretchToWindow();
+  waveTools->updateWaveform();
+
+  glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true);
+
+  redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitch()
+{
+  glue_setPitch(this, ch, pitch->value(), false);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitchNum()
+{
+  glue_setPitch(this, ch, atof(pitchNum->value()), true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitchHalf()
+{
+  glue_setPitch(this, ch, pitch->value()/2, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_setPitchDouble()
+{
+  glue_setPitch(this, ch, pitch->value()*2, true);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_zoomIn()
+{
+  waveTools->waveform->setZoom(-1);
+  waveTools->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_zoomOut()
+{
+  waveTools->waveform->setZoom(0);
+  waveTools->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdEditor::__cb_changeGrid()
+{
+  waveTools->waveform->setGridLevel(atoi(grid->text()));
+}
diff --git a/src/gui/dialogs/gd_editor.h b/src/gui/dialogs/gd_editor.h
new file mode 100644 (file)
index 0000000..54a8f79
--- /dev/null
@@ -0,0 +1,116 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_editor
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GD_EDITOR_H
+#define GD_EDITOR_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <math.h>
+#include "../elems/ge_window.h"
+
+
+class gdEditor : public gWindow {
+
+private:
+
+       static void cb_setChanPos    (Fl_Widget *w, void *p);
+       static void cb_resetStartEnd (Fl_Widget *w, void *p);
+       static void cb_setVolume     (Fl_Widget *w, void *p);
+       static void cb_setVolumeNum  (Fl_Widget *w, void *p);
+       static void cb_setBoost      (Fl_Widget *w, void *p);
+       static void cb_setBoostNum   (Fl_Widget *w, void *p);
+       static void cb_normalize     (Fl_Widget *w, void *p);
+       static void cb_panning       (Fl_Widget *w, void *p);
+       static void cb_reload        (Fl_Widget *w, void *p);
+       static void cb_setPitch      (Fl_Widget *w, void *p);
+       static void cb_setPitchToBar (Fl_Widget *w, void *p);
+       static void cb_setPitchToSong(Fl_Widget *w, void *p);
+       static void cb_setPitchHalf  (Fl_Widget *w, void *p);
+       static void cb_setPitchDouble(Fl_Widget *w, void *p);
+       static void cb_resetPitch    (Fl_Widget *w, void *p);
+       static void cb_setPitchNum   (Fl_Widget *w, void *p);
+       static void cb_zoomIn        (Fl_Widget *w, void *p);
+       static void cb_zoomOut       (Fl_Widget *w, void *p);
+       static void cb_changeGrid    (Fl_Widget *w, void *p);
+       static void cb_enableSnap    (Fl_Widget *w, void *p);
+       inline void __cb_setChanPos();
+       inline void __cb_resetStartEnd();
+       inline void __cb_setVolume();
+       inline void __cb_setVolumeNum();
+       inline void __cb_setBoost();
+       inline void __cb_setBoostNum();
+       inline void __cb_normalize();
+       inline void __cb_panning();
+       inline void __cb_reload();
+       inline void __cb_setPitch();
+       inline void __cb_setPitchToBar();
+       inline void __cb_setPitchToSong();
+       inline void __cb_setPitchHalf();
+       inline void __cb_setPitchDouble();
+       inline void __cb_resetPitch();
+       inline void __cb_setPitchNum();
+       inline void __cb_zoomIn();
+       inline void __cb_zoomOut();
+       inline void __cb_changeGrid();
+       inline void __cb_enableSnap();
+
+public:
+
+       gdEditor(class SampleChannel *ch);
+       ~gdEditor();
+
+       class gClick     *zoomIn;
+       class gClick     *zoomOut;
+       class gWaveTools *waveTools;
+       class gInput     *chanStart;
+       class gInput     *chanEnd;
+       class gClick             *resetStartEnd;
+       class gDial      *volume;
+       class gInput     *volumeNum;
+       class gDial      *boost;
+       class gInput     *boostNum;
+       class gClick     *normalize;
+       class gDial      *pan;
+       class gInput     *panNum;
+       class gClick             *reload;
+       class gDial              *pitch;
+       class gInput     *pitchNum;
+       class gClick     *pitchToBar;
+       class gClick     *pitchToSong;
+       class gClick     *pitchHalf;
+       class gClick     *pitchDouble;
+       class gClick     *pitchReset;
+       class gClick     *close;
+       class gChoice    *grid;
+       class gCheck     *snap;
+
+       class SampleChannel *ch;
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_keyGrabber.cpp b/src/gui/dialogs/gd_keyGrabber.cpp
new file mode 100644 (file)
index 0000000..6b4527f
--- /dev/null
@@ -0,0 +1,145 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_keyGrabber
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../utils/gui_utils.h"
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../utils/log.h"
+#include "../elems/ge_keyboard.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_channel.h"
+#include "../elems/ge_channelButton.h"
+#include "gd_keyGrabber.h"
+#include "gd_config.h"
+#include "gd_mainWindow.h"
+
+
+extern Conf             G_Conf;
+extern gdMainWindow *mainWin;
+
+
+gdKeyGrabber::gdKeyGrabber(Channel *ch)
+       : gWindow(300, 126, "Key configuration"), ch(ch)
+{
+       set_modal();
+       text   = new gBox(8, 8, 284, 80, "");
+       clear  = new gClick(w()-88, text->y()+text->h()+8, 80, 20, "Clear");
+       cancel = new gClick(clear->x()-88, clear->y(), 80, 20, "Close");
+       end();
+
+       clear->callback(cb_clear, (void*)this);
+       cancel->callback(cb_cancel, (void*)this);
+
+       updateText(ch->key);
+
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::cb_clear (Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_clear(); }
+void gdKeyGrabber::cb_cancel(Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_cancel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::__cb_cancel()
+{
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::__cb_clear()
+{
+       updateText(0);
+       setButtonLabel(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::setButtonLabel(int key)
+{
+       char tmp[2]; sprintf(tmp, "%c", key);
+       ch->guiChannel->mainButton->setKey(tmp);
+       ch->key = key;
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::updateText(int key)
+{
+       char tmp2[64];
+       if (key != 0)
+               sprintf(tmp2, "Press a key.\n\nCurrent binding: %c", key);
+       else
+               sprintf(tmp2, "Press a key.\n\nCurrent binding: [none]");
+       text->copy_label(tmp2);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gdKeyGrabber::handle(int e)
+{
+       int ret = Fl_Group::handle(e);
+       switch(e) {
+               case FL_KEYUP: {
+                       int x = Fl::event_key();
+                       if (strlen(Fl::event_text()) != 0
+                           && x != FL_BackSpace
+                           && x != FL_Enter
+                           && x != FL_Delete
+                           && x != FL_Tab
+                           && x != FL_End
+                           && x != ' ')
+                       {
+                               gLog("set key '%c' (%d) for channel %d\n", x, x, ch->index);
+                               setButtonLabel(x);
+                               updateText(x);
+                               break;
+                       }
+                       else
+                               gLog("invalid key\n");
+               }
+       }
+       return(ret);
+}
diff --git a/src/gui/dialogs/gd_keyGrabber.h b/src/gui/dialogs/gd_keyGrabber.h
new file mode 100644 (file)
index 0000000..02bbe85
--- /dev/null
@@ -0,0 +1,63 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_keyGrabber
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_KEYGRABBER_H
+#define GD_KEYGRABBER_H
+
+
+#include <FL/Fl.H>
+#include "../elems/ge_window.h"
+
+
+class gdKeyGrabber : public gWindow
+{
+private:
+
+       class Channel *ch;
+
+       class gBox   *text;
+       class gClick *clear;
+       class gClick *cancel;
+
+       static void cb_clear (Fl_Widget *w, void *p);
+       static void cb_cancel(Fl_Widget *w, void *p);
+       inline void __cb_clear ();
+       inline void __cb_cancel();
+
+       void setButtonLabel(int key);
+
+       void updateText(int key);
+
+public:
+
+       gdKeyGrabber(class Channel *ch);
+       int handle(int e);
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp
new file mode 100644 (file)
index 0000000..0289763
--- /dev/null
@@ -0,0 +1,543 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_mainWindow
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef __linux__
+       #include <sys/stat.h>                   // for mkdir
+#endif
+
+
+#include "../../core/graphics.h"
+#include "../../core/mixer.h"
+#include "../../core/recorder.h"
+#include "../../core/mixerHandler.h"
+#include "../../core/pluginHost.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/init.h"
+#include "../../core/patch.h"
+#include "../../core/conf.h"
+#include "../../glue/glue.h"
+#include "../elems/ge_keyboard.h"
+#include "gd_warnings.h"
+#include "gd_bpmInput.h"
+#include "gd_beatsInput.h"
+#include "gd_midiInput.h"
+#include "gd_about.h"
+#include "gd_config.h"
+#include "gd_browser.h"
+#include "gd_mainWindow.h"
+
+
+#ifdef WITH_VST
+#include "gd_pluginList.h"
+#endif
+
+
+extern Mixer                    G_Mixer;
+extern Patch                    G_Patch;
+extern Conf                             G_Conf;
+extern gdMainWindow *mainWin;
+extern bool                                     G_quit;
+extern bool                             G_audio_status;
+
+#if defined(WITH_VST)
+extern PluginHost       G_PluginHost;
+#endif
+
+
+gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **argv)
+       : gWindow(W, H, title)
+{
+       Fl::visible_focus(0);
+       Fl::background(25, 25, 25);
+       Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2);    // custom box G_BOX
+
+       size_range(GUI_WIDTH, GUI_HEIGHT);
+
+       menu       = new gMenu(8, -1);
+       inOut      = new gInOut(408, 8);
+       controller = new gController(8, 39);
+       timing     = new gTiming(632, 39);
+       beatMeter  = new gBeatMeter(100, 83, 609, 20);
+       keyboard   = new gKeyboard(8, 122, w()-16, 380);
+
+       /* zone 1 - menus, and I/O tools */
+
+       Fl_Group *zone1 = new Fl_Group(8, 8, W-16, 20);
+       zone1->add(menu);
+       zone1->resizable(new Fl_Box(300, 8, 80, 20));
+       zone1->add(inOut);
+
+       /* zone 2 - controller and timing tools */
+
+       Fl_Group *zone2 = new Fl_Group(8, controller->y(), W-16, controller->h());
+       zone2->add(controller);
+       zone2->resizable(new Fl_Box(controller->x()+controller->w()+4, zone2->y(), 80, 20));
+       zone2->add(timing);
+
+       /* zone 3 - beat meter */
+
+       Fl_Group *zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h());
+       zone3->add(beatMeter);
+
+       /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
+        * a group by itself) */
+
+       resizable(keyboard);
+
+       add(zone1);
+       add(zone2);
+       add(zone3);
+       add(keyboard);
+       callback(cb_endprogram);
+       gu_setFavicon(this);
+       show(argc, argv);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { mainWin->__cb_endprogram(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gdMainWindow::__cb_endprogram()
+{
+       if (!gdConfirmWin("Warning", "Quit Giada: are you sure?"))
+               return;
+       init_shutdown();
+       hide();
+       delete this;
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gInOut::gInOut(int x, int y)
+       : Fl_Group(x, y, 394, 20)
+{
+       begin();
+
+#if defined(WITH_VST)
+       masterFxIn  = new gFxButton  (x, y, 20, 20, fxOff_xpm, fxOn_xpm);
+       inVol               = new gDial      (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20);
+       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
+       inToOut     = new gClick     (inMeter->x()+inMeter->w()+4, y+5, 10, 10, "");
+       outMeter    = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+5, 140, 10);
+       outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
+       masterFxOut = new gFxButton  (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm);
+#else
+       inVol               = new gDial      (x+62, y, 20, 20);
+       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
+       outMeter    = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 10);
+       outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
+#endif
+
+       end();
+
+       resizable(NULL);   // don't resize any widget
+
+       outVol->callback(cb_outVol, (void*)this);
+       outVol->value(G_Mixer.outVol);
+       inVol->callback(cb_inVol, (void*)this);
+       inVol->value(G_Mixer.inVol);
+
+#ifdef WITH_VST
+       masterFxOut->callback(cb_masterFxOut, (void*)this);
+       masterFxIn->callback(cb_masterFxIn, (void*)this);
+       inToOut->callback(cb_inToOut, (void*)this);
+       inToOut->type(FL_TOGGLE_BUTTON);
+#endif
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gInOut::cb_outVol     (Fl_Widget *v, void *p)     { ((gInOut*)p)->__cb_outVol(); }
+void gInOut::cb_inVol      (Fl_Widget *v, void *p)     { ((gInOut*)p)->__cb_inVol(); }
+#ifdef WITH_VST
+void gInOut::cb_masterFxOut(Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_masterFxOut(); }
+void gInOut::cb_masterFxIn (Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_masterFxIn(); }
+void gInOut::cb_inToOut    (Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_inToOut(); }
+#endif
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gInOut::__cb_outVol()
+{
+       glue_setOutVol(outVol->value());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gInOut::__cb_inVol()
+{
+       glue_setInVol(inVol->value());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+void gInOut::__cb_masterFxOut()
+{
+       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST);
+}
+
+void gInOut::__cb_masterFxIn()
+{
+       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST);
+}
+
+void gInOut::__cb_inToOut()
+{
+       G_Mixer.inToOut = inToOut->value();
+}
+#endif
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gInOut::refresh()
+{
+       outMeter->mixerPeak = G_Mixer.peakOut;
+       inMeter->mixerPeak  = G_Mixer.peakIn;
+       outMeter->redraw();
+       inMeter->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gMenu::gMenu(int x, int y)
+       : Fl_Group(x, y, 300, 20)
+{
+       begin();
+
+       file   = new gClick(x, y, 70, 21, "file");
+       edit   = new gClick(file->x()+file->w()+4,  y, 70, 21, "edit");
+       config = new gClick(edit->x()+edit->w()+4, y, 70, 21, "config");
+       about    = new gClick(config->x()+config->w()+4, y, 70, 21, "about");
+
+       end();
+
+       resizable(NULL);   // don't resize any widget
+
+       about->callback(cb_about, (void*)this);
+       file->callback(cb_file, (void*)this);
+       edit->callback(cb_edit, (void*)this);
+       config->callback(cb_config, (void*)this);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); }
+void gMenu::cb_config(Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_config(); }
+void gMenu::cb_file  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); }
+void gMenu::cb_edit  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMenu::__cb_about()
+{
+       gu_openSubWindow(mainWin, new gdAbout(), WID_ABOUT);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMenu::__cb_config()
+{
+       gu_openSubWindow(mainWin, new gdConfig(380, 370), WID_CONFIG);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMenu::__cb_file()
+{
+       /* An Fl_Menu_Button is made of many Fl_Menu_Item */
+
+       Fl_Menu_Item menu[] = {
+               {"Open patch or project..."},
+               {"Save patch..."},
+               {"Save project..."},
+               {"Quit Giada"},
+               {0}
+       };
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(11);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = menu->popup(Fl::event_x(),      Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+
+       if (strcmp(m->label(), "Open patch or project...") == 0) {
+               gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath, 0, BROWSER_LOAD_PATCH);
+               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               return;
+       }
+       if (strcmp(m->label(), "Save patch...") == 0) {
+               if (G_Mixer.hasLogicalSamples() || G_Mixer.hasEditedSamples())
+                       if (!gdConfirmWin("Warning", "You should save a project in order to store\nyour takes and/or processed samples."))
+                               return;
+               gWindow *childWin = new gdBrowser("Save Patch", G_Conf.patchPath, 0, BROWSER_SAVE_PATCH);
+               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               return;
+       }
+       if (strcmp(m->label(), "Save project...") == 0) {
+               gWindow *childWin = new gdBrowser("Save Project", G_Conf.patchPath, 0, BROWSER_SAVE_PROJECT);
+               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               return;
+       }
+       if (strcmp(m->label(), "Quit Giada") == 0) {
+               mainWin->do_callback();
+               return;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMenu::__cb_edit()
+{
+       Fl_Menu_Item menu[] = {
+               {"Clear all samples"},
+               {"Clear all actions"},
+               {"Remove empty columns"},
+               {"Reset to init state"},
+               {"Setup global MIDI input..."},
+               {0}
+       };
+
+       /* clear all actions disabled if no recs, clear all samples disabled
+        * if no samples. */
+
+       menu[1].deactivate();
+
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               if (G_Mixer.channels.at(i)->hasActions) {
+                       menu[1].activate();
+                       break;
+               }
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
+                       if (((SampleChannel*)G_Mixer.channels.at(i))->wave != NULL) {
+                               menu[0].activate();
+                               break;
+                       }
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(11);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = menu->popup(Fl::event_x(),      Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+       if (strcmp(m->label(), "Clear all samples") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all samples: are you sure?"))
+                       return;
+               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
+               glue_clearAllSamples();
+               return;
+       }
+       if (strcmp(m->label(), "Clear all actions") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+                       return;
+               mainWin->delSubWindow(WID_ACTION_EDITOR);
+               glue_clearAllRecs();
+               return;
+       }
+       if (strcmp(m->label(), "Reset to init state") == 0) {
+               if (!gdConfirmWin("Warning", "Reset to init state: are you sure?"))
+                       return;
+               gu_closeAllSubwindows();
+               glue_resetToInitState();
+               return;
+       }
+       if (strcmp(m->label(), "Remove empty columns") == 0) {
+               mainWin->keyboard->organizeColumns();
+               return;
+       }
+       if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0);
+               return;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gTiming::gTiming(int x, int y)
+       : Fl_Group(x, y, 170, 15)
+{
+       begin();
+
+       quantizer  = new gChoice(x, y, 40, 15, "", false);
+       bpm        = new gClick (quantizer->x()+quantizer->w()+4,  y, 40, 15);
+       meter      = new gClick (bpm->x()+bpm->w()+8,  y, 40, 15, "4/1");
+       multiplier = new gClick (meter->x()+meter->w()+4, y, 15, 15, "", beatsMultiplyOff_xpm, beatsMultiplyOn_xpm);
+       divider    = new gClick (multiplier->x()+multiplier->w()+4, y, 15, 15, "÷", beatsDivideOff_xpm, beatsDivideOn_xpm);
+
+       end();
+
+       resizable(NULL);   // don't resize any widget
+
+       char buf[6]; snprintf(buf, 6, "%f", G_Mixer.bpm);
+       bpm->copy_label(buf);
+
+       bpm->callback(cb_bpm, (void*)this);
+       meter->callback(cb_meter, (void*)this);
+       multiplier->callback(cb_multiplier, (void*)this);
+       divider->callback(cb_divider, (void*)this);
+
+       quantizer->add("off", 0, cb_quantizer, (void*)this);
+       quantizer->add("1b",  0, cb_quantizer, (void*)this);
+       quantizer->add("2b",  0, cb_quantizer, (void*)this);
+       quantizer->add("3b",  0, cb_quantizer, (void*)this);
+       quantizer->add("4b",  0, cb_quantizer, (void*)this);
+       quantizer->add("6b",  0, cb_quantizer, (void*)this);
+       quantizer->add("8b",  0, cb_quantizer, (void*)this);
+       quantizer->value(0); //  "off" by default
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::cb_bpm       (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); }
+void gTiming::cb_meter     (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_meter(); }
+void gTiming::cb_quantizer (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_quantizer(); }
+void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multiplier(); }
+void gTiming::cb_divider   (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::__cb_bpm()
+{
+       gu_openSubWindow(mainWin, new gdBpmInput(bpm->label()), WID_BPM);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::__cb_meter()
+{
+       gu_openSubWindow(mainWin, new gdBeatsInput(), WID_BEATS);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::__cb_quantizer()
+{
+       glue_quantize(quantizer->value());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::__cb_multiplier()
+{
+       glue_beatsMultiply();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::__cb_divider()
+{
+       glue_beatsDivide();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::setBpm(const char *v)
+{
+       bpm->copy_label(v);
+}
+
+
+void gTiming::setBpm(float v)
+{
+       char buf[6];
+       sprintf(buf, "%.01f", v);  // only 1 decimal place (e.g. 120.0)
+       bpm->copy_label(buf);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gTiming::setMeter(int beats, int bars)
+{
+       char buf[8];
+       sprintf(buf, "%d/%d", beats, bars);
+       meter->copy_label(buf);
+}
diff --git a/src/gui/dialogs/gd_mainWindow.h b/src/gui/dialogs/gd_mainWindow.h
new file mode 100644 (file)
index 0000000..df2c911
--- /dev/null
@@ -0,0 +1,175 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ * gd_mainWindow
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_MAINWINDOW_H
+#define GD_MAINWINDOW_H
+
+
+#include <FL/Fl.H>
+#include <FL/x.H>
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_window.h"
+#include "../elems/ge_controller.h"
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gdMainWindow : public gWindow
+{
+private:
+
+       static void cb_endprogram  (Fl_Widget *v, void *p);
+       inline void __cb_endprogram();
+
+public:
+
+       class gKeyboard   *keyboard;
+       class gBeatMeter  *beatMeter;
+       class gMenu       *menu;
+       class gInOut      *inOut;
+       class gController *controller;
+       class gTiming     *timing;
+
+       gdMainWindow(int w, int h, const char *title, int argc, char **argv);
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gInOut : public Fl_Group
+{
+private:
+
+       class gSoundMeter *outMeter;
+       class gSoundMeter *inMeter;
+       class gBeatMeter  *beatMeter;
+       class gDial                             *outVol;
+       class gDial                             *inVol;
+#ifdef WITH_VST
+       class gFxButton         *masterFxOut;
+       class gFxButton         *masterFxIn;
+       class gClick      *inToOut;
+#endif
+
+       static void cb_outVol     (Fl_Widget *v, void *p);
+       static void cb_inVol      (Fl_Widget *v, void *p);
+#ifdef WITH_VST
+       static void cb_masterFxOut(Fl_Widget *v, void *p);
+       static void cb_masterFxIn (Fl_Widget *v, void *p);
+       static void cb_inToOut    (Fl_Widget *v, void *p);
+#endif
+
+       inline void __cb_outVol     ();
+       inline void __cb_inVol      ();
+#ifdef WITH_VST
+       inline void __cb_masterFxOut();
+       inline void __cb_masterFxIn ();
+       inline void __cb_inToOut    ();
+#endif
+
+public:
+
+       gInOut(int x, int y);
+
+       void refresh();
+
+       inline void setOutVol(float v) { outVol->value(v); }
+       inline void setInVol (float v) { inVol->value(v); }
+#ifdef WITH_VST
+       inline void setMasterFxOutFull(bool v) { masterFxOut->full = v; masterFxOut->redraw(); }
+       inline void setMasterFxInFull(bool v)  { masterFxIn->full = v; masterFxIn->redraw(); }
+#endif
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gMenu : public Fl_Group
+{
+private:
+
+       class gClick *file;
+       class gClick *edit;
+       class   gClick *config;
+       class gClick *about;
+
+       static void cb_about (Fl_Widget *v, void *p);
+       static void cb_config(Fl_Widget *v, void *p);
+       static void cb_file  (Fl_Widget *v, void *p);
+       static void cb_edit  (Fl_Widget *v, void *p);
+
+       inline void __cb_about ();
+       inline void __cb_config();
+       inline void __cb_file  ();
+       inline void __cb_edit  ();
+
+public:
+
+       gMenu(int x, int y);
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gTiming : public Fl_Group
+{
+private:
+
+       class gClick   *bpm;
+       class gClick   *meter;
+       class gChoice  *quantizer;
+       class gClick   *multiplier;
+       class gClick   *divider;
+
+       static void cb_bpm       (Fl_Widget *v, void *p);
+       static void cb_meter     (Fl_Widget *v, void *p);
+       static void cb_quantizer (Fl_Widget *v, void *p);
+       static void cb_multiplier(Fl_Widget *v, void *p);
+       static void cb_divider   (Fl_Widget *v, void *p);
+
+       inline void __cb_bpm();
+       inline void __cb_meter();
+       inline void __cb_quantizer();
+       inline void __cb_multiplier();
+       inline void __cb_divider();
+
+public:
+
+       gTiming(int x, int y);
+
+       void setBpm(const char *v);
+       void setBpm(float v);
+       void setMeter(int beats, int bars);
+};
+
+
+#endif
diff --git a/src/gui/dialogs/gd_midiInput.cpp b/src/gui/dialogs/gd_midiInput.cpp
new file mode 100644 (file)
index 0000000..27a7d67
--- /dev/null
@@ -0,0 +1,184 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiInput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../utils/gui_utils.h"
+#include "../../core/kernelMidi.h"
+#include "../../core/conf.h"
+#include "../../core/sampleChannel.h"
+#include "../../utils/log.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_midiIoTools.h"
+#include "gd_midiInput.h"
+
+
+extern Conf G_Conf;
+
+
+gdMidiInput::gdMidiInput(int w, int h, const char *title)
+       : gWindow(w, h, title)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInput::~gdMidiInput() {
+       kernelMidi::stopMidiLearn();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::stopMidiLearn(gLearner *learner) {
+       kernelMidi::stopMidiLearn();
+       learner->updateValue();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+       *param = msg;
+       stopMidiLearn(l);
+       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::cb_learn(uint32_t msg, void *d) {
+       cbData *data = (cbData*) d;
+       gdMidiInput   *window  = (gdMidiInput*) data->window;
+       gLearner      *learner = data->learner;
+       uint32_t      *param   = learner->param;
+       window->__cb_learn(param, msg, learner);
+       free(data);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiInput*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::__cb_close() {
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
+       :       gdMidiInput(300, 206, "MIDI Input Setup"),
+               ch(ch)
+{
+       char title[64];
+       sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1);
+       label(title);
+
+       set_modal();
+
+       enable = new gCheck(8, 8, 120, 20, "enable MIDI input");
+       new gLearner(8,  30, w()-16, "key press",   cb_learn, &ch->midiInKeyPress);
+       new gLearner(8,  54, w()-16, "key release", cb_learn, &ch->midiInKeyRel);
+       new gLearner(8,  78, w()-16, "key kill",    cb_learn, &ch->midiInKill);
+       new gLearner(8, 102, w()-16, "mute",        cb_learn, &ch->midiInMute);
+       new gLearner(8, 126, w()-16, "solo",        cb_learn, &ch->midiInSolo);
+       new gLearner(8, 150, w()-16, "volume",      cb_learn, &ch->midiInVolume);
+       int yy = 178;
+
+       if (ch->type == CHANNEL_SAMPLE) {
+               size(300, 254);
+               new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
+               new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
+               yy = 226;
+       }
+
+       ok = new gButton(w()-88, yy, 80, 20, "Close");
+       ok->callback(cb_close, (void*)this);
+
+       enable->value(ch->midiIn);
+       enable->callback(cb_enable, (void*)this);
+
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiInputChannel*)p)->__cb_enable(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputChannel::__cb_enable() {
+       ch->midiIn = enable->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInputMaster::gdMidiInputMaster()
+       : gdMidiInput(300, 256, "MIDI Input Setup (global)")
+{
+       set_modal();
+
+       new gLearner(8,   8, w()-16, "rewind",           &cb_learn, &G_Conf.midiInRewind);
+       new gLearner(8,  32, w()-16, "play/stop",        &cb_learn, &G_Conf.midiInStartStop);
+       new gLearner(8,  56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec);
+       new gLearner(8,  80, w()-16, "input recording",  &cb_learn, &G_Conf.midiInInputRec);
+       new gLearner(8, 104, w()-16, "metronome",        &cb_learn, &G_Conf.midiInMetronome);
+       new gLearner(8, 128, w()-16, "input volume",     &cb_learn, &G_Conf.midiInVolumeIn);
+       new gLearner(8, 152, w()-16, "output volume",    &cb_learn, &G_Conf.midiInVolumeOut);
+       new gLearner(8, 176, w()-16, "sequencer ×2",     &cb_learn, &G_Conf.midiInBeatDouble);
+       new gLearner(8, 200, w()-16, "sequencer ÷2",     &cb_learn, &G_Conf.midiInBeatHalf);
+       ok = new gButton(w()-88, 228, 80, 20, "Close");
+
+       ok->callback(cb_close, (void*)this);
+
+       gu_setFavicon(this);
+       show();
+}
diff --git a/src/gui/dialogs/gd_midiInput.h b/src/gui/dialogs/gd_midiInput.h
new file mode 100644 (file)
index 0000000..e5d31f5
--- /dev/null
@@ -0,0 +1,98 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiInput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_MIDI_INPUT_H
+#define GD_MIDI_INPUT_H
+
+
+#include "../../core/kernelMidi.h"
+#include "../../utils/utils.h"
+#include "../elems/ge_window.h"
+#include "../elems/ge_mixed.h"
+
+
+class gdMidiInput : public gWindow
+{
+protected:
+
+       gClick *ok;
+
+       void stopMidiLearn(class gLearner *l);
+
+       /* cb_learn
+        * callback attached to kernelMidi to learn various actions. */
+
+       static void cb_learn  (uint32_t msg, void *data);
+       inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l);
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+public:
+
+       gdMidiInput(int w, int h, const char *title);
+       ~gdMidiInput();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiInputChannel : public gdMidiInput
+{
+private:
+
+       class Channel *ch;
+
+       gCheck *enable;
+
+
+       //gVector <gLearner *> items; for future use, with vst parameters
+
+       static void cb_enable  (Fl_Widget *w, void *p);
+       inline void __cb_enable();
+
+public:
+
+       gdMidiInputChannel(class Channel *ch);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiInputMaster : public gdMidiInput
+{
+public:
+
+       gdMidiInputMaster();
+};
+
+
+#endif
diff --git a/src/gui/dialogs/gd_midiOutput.cpp b/src/gui/dialogs/gd_midiOutput.cpp
new file mode 100644 (file)
index 0000000..991b68a
--- /dev/null
@@ -0,0 +1,249 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiOutput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/conf.h"
+#include "../../core/midiChannel.h"
+#include "../../utils/gui_utils.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_channel.h"
+#include "../elems/ge_midiIoTools.h"
+#include "../elems/ge_keyboard.h"
+#include "gd_midiOutput.h"
+
+
+extern Conf    G_Conf;
+
+
+gdMidiOutput::gdMidiOutput(int w, int h)
+       //: gWindow(300, 64, "Midi Output Setup")
+       : gWindow(w, h, "Midi Output Setup")
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::stopMidiLearn(gLearner *learner) {
+       kernelMidi::stopMidiLearn();
+       learner->updateValue();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+       *param = msg;
+       stopMidiLearn(l);
+       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_learn(uint32_t msg, void *d) {
+       cbData *data = (cbData*) d;
+       gdMidiOutput  *window  = (gdMidiOutput*) data->window;
+       gLearner      *learner = data->learner;
+       uint32_t      *param   = learner->param;
+       window->__cb_learn(param, msg, learner);
+       free(data);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiOutput*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_close() {
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p)  {
+       ((gdMidiOutput*)p)->__cb_enableLightning();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_enableLightning() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::setTitle(int chanNum)
+{
+       char title[64];
+       sprintf(title, "MIDI Output Setup (channel %d)", chanNum);
+       copy_label(title);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch)
+       : gdMidiOutput(300, 168), ch(ch)
+{
+       setTitle(ch->index+1);
+       begin();
+
+       enableOut   = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output");
+       chanListOut = new gChoice(w()-108, y()+8, 100, 20);
+
+       enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output");
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+8,  w()-16, "playing", cb_learn, &ch->midiOutLplaying);
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",    cb_learn, &ch->midiOutLmute);
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",    cb_learn, &ch->midiOutLsolo);
+
+       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
+
+       end();
+
+       chanListOut->add("Channel 1");
+       chanListOut->add("Channel 2");
+       chanListOut->add("Channel 3");
+       chanListOut->add("Channel 4");
+       chanListOut->add("Channel 5");
+       chanListOut->add("Channel 6");
+       chanListOut->add("Channel 7");
+       chanListOut->add("Channel 8");
+       chanListOut->add("Channel 9");
+       chanListOut->add("Channel 10");
+       chanListOut->add("Channel 11");
+       chanListOut->add("Channel 12");
+       chanListOut->add("Channel 13");
+       chanListOut->add("Channel 14");
+       chanListOut->add("Channel 15");
+       chanListOut->add("Channel 16");
+       chanListOut->value(0);
+
+       if (ch->midiOut)
+               enableOut->value(1);
+       else
+               chanListOut->deactivate();
+
+       if (ch->midiOutL)
+               enableLightning->value(1);
+
+       chanListOut->value(ch->midiOutChan);
+
+       enableOut->callback(cb_enableChanList, (void*)this);
+       close->callback(cb_close, (void*)this);
+
+       set_modal();
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::cb_close         (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); }
+void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::__cb_enableChanList() {
+       enableOut->value() ? chanListOut->activate() : chanListOut->deactivate();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::__cb_close() {
+       ch->midiOut     = enableOut->value();
+       ch->midiOutChan = chanListOut->value();
+       ch->midiOutL    = enableLightning->value();
+       ch->guiChannel->update();
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch)
+       : gdMidiOutput(300, 140), ch(ch)
+{
+       setTitle(ch->index+1);
+
+       enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output");
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying);
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",   cb_learn, &ch->midiOutLmute);
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",   cb_learn, &ch->midiOutLsolo);
+
+       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
+       close->callback(cb_close, (void*)this);
+
+       enableLightning->value(ch->midiOutL);
+       enableLightning->callback(cb_enableLightning, (void*)this);
+
+       set_modal();
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputSampleCh::__cb_close() {
+       ch->midiOutL = enableLightning->value();
+       do_callback();
+}
diff --git a/src/gui/dialogs/gd_midiOutput.h b/src/gui/dialogs/gd_midiOutput.h
new file mode 100644 (file)
index 0000000..911a253
--- /dev/null
@@ -0,0 +1,134 @@
+/* ----------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiOutput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GD_MIDI_OUTPUT_H
+#define GD_MIDI_OUTPUT_H
+
+
+#include <FL/Fl.H>
+#include <stdint.h>
+#include "../elems/ge_window.h"
+
+
+/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI
+output master is managed by the configuration window, hence gdMidiOutput deals
+only with channels.
+
+Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set.
+In addition MidiOutputMidiCh has the MIDI message output box. */
+
+/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another
+parent class gdMidiIO to inherit from */
+
+class gdMidiOutput : public gWindow
+{
+protected:
+
+       class gClick *close;
+       class gCheck *enableLightning;
+
+       void stopMidiLearn(class gLearner *l);
+
+       /* cb_learn
+        * callback attached to kernelMidi to learn various actions. */
+
+       static void cb_learn  (uint32_t msg, void *data);
+       inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l);
+
+       /* cb_close
+       close current window. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+       /* cb_enableLightning
+       enable MIDI lightning output. */
+
+       static void cb_enableLightning  (Fl_Widget *w, void *p);
+       inline void __cb_enableLightning();
+
+       /* setTitle
+        * set window title. */
+
+       void setTitle(int chanNum);
+
+public:
+
+       gdMidiOutput(int w, int h);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiOutputMidiCh : public gdMidiOutput
+{
+private:
+
+       static void cb_enableChanList  (Fl_Widget *w, void *p);
+       inline void __cb_enableChanList();
+
+       /* __cb_close
+       override parent method, we need to do more stuff on close. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+       class gCheck  *enableOut;
+       class gChoice *chanListOut;
+
+       class MidiChannel *ch;
+
+public:
+
+       gdMidiOutputMidiCh(class MidiChannel *ch);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiOutputSampleCh : public gdMidiOutput
+{
+private:
+
+       class SampleChannel *ch;
+
+       /* __cb_close
+       override parent method, we need to do more stuff on close. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+public:
+
+       gdMidiOutputSampleCh(class SampleChannel *ch);
+};
+
+#endif
diff --git a/src/gui/dialogs/gd_pluginList.cpp b/src/gui/dialogs/gd_pluginList.cpp
new file mode 100644 (file)
index 0000000..6ef967d
--- /dev/null
@@ -0,0 +1,394 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginList
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+
+#include "../../utils/gui_utils.h"
+#include "../../utils/utils.h"
+#include "../../core/conf.h"
+#include "../../core/graphics.h"
+#include "../../core/pluginHost.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_channel.h"
+#include "gd_pluginList.h"
+#include "gd_pluginWindow.h"
+#include "gd_pluginWindowGUI.h"
+#include "gd_browser.h"
+#include "gd_mainWindow.h"
+
+
+extern Conf          G_Conf;
+extern PluginHost    G_PluginHost;
+extern gdMainWindow *mainWin;
+
+
+gdPluginList::gdPluginList(int stackType, Channel *ch)
+ : gWindow(468, 204), ch(ch), stackType(stackType)
+{
+
+       if (G_Conf.pluginListX)
+               resize(G_Conf.pluginListX, G_Conf.pluginListY, w(), h());
+
+       list = new Fl_Scroll(8, 8, 476, 188);
+       list->type(Fl_Scroll::VERTICAL);
+       list->scrollbar.color(COLOR_BG_0);
+       list->scrollbar.selection_color(COLOR_BG_1);
+       list->scrollbar.labelcolor(COLOR_BD_1);
+       list->scrollbar.slider(G_BOX);
+
+       list->begin();
+               refreshList();
+       list->end();
+
+       end();
+       set_non_modal();
+
+  /* TODO - awful stuff... we should subclass into gdPluginListChannel and
+  gdPluginListMaster */
+
+       if (stackType == PluginHost::MASTER_OUT)
+               label("Master Out Plugins");
+       else
+       if (stackType == PluginHost::MASTER_IN)
+               label("Master In Plugins");
+       else {
+               char tmp[32];
+               sprintf(tmp, "Channel %d Plugins", ch->index+1);
+               copy_label(tmp);
+       }
+
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdPluginList::~gdPluginList() {
+       G_Conf.pluginListX = x();
+       G_Conf.pluginListY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::cb_addPlugin(Fl_Widget *v, void *p)   { ((gdPluginList*)p)->__cb_addPlugin(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) {
+
+       /* note: this callback is fired by gdBrowser. Close its window first,
+        * by calling the parent (pluginList) and telling it to delete its
+        * subwindow (i.e. gdBrowser). */
+
+       gWindow *child = (gWindow*) v;
+       if (child->getParent() != NULL)
+               (child->getParent())->delSubWindow(child);
+
+       /* finally refresh plugin list: void *p is a pointer to gdPluginList.
+        * This callback works even when you click 'x' to close the window...
+        * well, who cares */
+
+       ((gdPluginList*)p)->refreshList();
+       ((gdPluginList*)p)->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::__cb_addPlugin() {
+
+       /* the usual callback that gWindow adds to each subwindow in this case
+        * is not enough, because when we close the browser the plugin list
+        * must be redrawn. We have a special callback, cb_refreshList, which
+        * we add to gdBrowser. It does exactly what we need. */
+
+       gdBrowser *b = new gdBrowser("Browse Plugin", G_Conf.pluginPath, ch, BROWSER_LOAD_PLUGIN, stackType);
+       addSubWindow(b);
+       b->callback(cb_refreshList, (void*)this);       // 'this' refers to gdPluginList
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::refreshList() {
+
+       /* delete the previous list */
+
+       list->clear();
+       list->scroll_to(0, 0);
+
+       /* add new buttons, as many as the plugin in pluginHost::stack + 1,
+        * the 'add new' button. Warning: if ch == NULL we are working with
+        * master in/master out stacks. */
+
+       int numPlugins = G_PluginHost.countPlugins(stackType, ch);
+       int i = 0;
+
+       while (i<numPlugins) {
+               Plugin   *pPlugin  = G_PluginHost.getPluginByIndex(i, stackType, ch);
+               gdPlugin *gdp      = new gdPlugin(this, pPlugin, list->x(), list->y()-list->yposition()+(i*24), 800);
+               list->add(gdp);
+               i++;
+       }
+
+       int addPlugY = numPlugins == 0 ? 90 : list->y()-list->yposition()+(i*24);
+       addPlugin = new gClick(8, addPlugY, 452, 20, "-- add new plugin --");
+       addPlugin->callback(cb_addPlugin, (void*)this);
+       list->add(addPlugin);
+
+       /* if num(plugins) > 7 make room for the side scrollbar.
+        * Scrollbar.width = 20 + 4(margin) */
+
+       if (i>7)
+               size(492, h());
+       else
+               size(468, h());
+
+       redraw();
+
+  /* set 'full' flag to FX button */
+  
+  /* TODO - awful stuff... we should subclass into gdPluginListChannel and
+  gdPluginListMaster */
+
+       if (stackType == PluginHost::MASTER_OUT) {
+    mainWin->inOut->setMasterFxOutFull(G_PluginHost.countPlugins(stackType, ch) > 0);
+  }
+       else
+       if (stackType == PluginHost::MASTER_IN) {
+    mainWin->inOut->setMasterFxInFull(G_PluginHost.countPlugins(stackType, ch) > 0);
+  }
+       else {
+    ch->guiChannel->fx->full = G_PluginHost.countPlugins(stackType, ch) > 0;
+    ch->guiChannel->fx->redraw();
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdPlugin::gdPlugin(gdPluginList *gdp, Plugin *p, int X, int Y, int W)
+       : Fl_Group(X, Y, W, 20), pParent(gdp), pPlugin (p)
+{
+       begin();
+       button    = new gButton(8, y(), 220, 20);
+       program   = new gChoice(button->x()+button->w()+4, y(), 132, 20);
+       bypass    = new gButton(program->x()+program->w()+4, y(), 20, 20);
+       shiftUp   = new gButton(bypass->x()+bypass->w()+4, y(), 20, 20, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm);
+       shiftDown = new gButton(shiftUp->x()+shiftUp->w()+4, y(), 20, 20, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm);
+       remove    = new gButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm);
+       end();
+
+       if (pPlugin->status != 1) {  // bad state
+               char name[256];
+               sprintf(name, "* %s *", gBasename(pPlugin->pathfile).c_str());
+               button->copy_label(name);
+       }
+       else {
+               char name[256];
+               pPlugin->getProduct(name);
+               if (strcmp(name, " ")==0)
+                       pPlugin->getName(name);
+
+               button->copy_label(name);
+               button->callback(cb_openPluginWindow, (void*)this);
+
+               program->callback(cb_setProgram, (void*)this);
+
+               /* loading vst programs */
+               /* FIXME - max programs = 128 (unknown source) */
+
+               for (int i=0; i<64; i++) {
+                       char out[kVstMaxProgNameLen];
+                       pPlugin->getProgramName(i, out);
+                       for (int j=0; j<kVstMaxProgNameLen; j++)  // escape FLTK special chars
+                               if (out[j] == '/' || out[j] == '\\' || out[j] == '&' || out[j] == '_')
+                                       out[j] = '-';
+                       if (strlen(out) > 0)
+                               program->add(out);
+               }
+               if (program->size() == 0) {
+                       program->add("-- no programs --\0");
+                       program->deactivate();
+               }
+               if (pPlugin->getProgram() == -1)
+                       program->value(0);
+               else
+                       program->value(pPlugin->getProgram());
+
+               bypass->callback(cb_setBypass, (void*)this);
+               bypass->type(FL_TOGGLE_BUTTON);
+               bypass->value(pPlugin->bypass ? 0 : 1);
+       }
+
+       shiftUp->callback(cb_shiftUp, (void*)this);
+       shiftDown->callback(cb_shiftDown, (void*)this);
+       remove->callback(cb_removePlugin, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::cb_removePlugin    (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_removePlugin(); }
+void gdPlugin::cb_openPluginWindow(Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_openPluginWindow(); }
+void gdPlugin::cb_setBypass       (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_setBypass(); }
+void gdPlugin::cb_shiftUp         (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_shiftUp(); }
+void gdPlugin::cb_shiftDown       (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_shiftDown(); }
+void gdPlugin::cb_setProgram      (Fl_Widget *v, void *p)    { ((gdPlugin*)p)->__cb_setProgram(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_shiftUp() {
+
+       /*nothing to do if there's only one plugin */
+
+       if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1)
+               return;
+
+       int pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
+
+       if (pluginIndex == 0)  // first of the stack, do nothing
+               return;
+
+       G_PluginHost.swapPlugin(pluginIndex, pluginIndex-1, pParent->stackType, pParent->ch);
+       pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_shiftDown() {
+
+       /*nothing to do if there's only one plugin */
+
+       if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1)
+               return;
+
+       unsigned pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
+       unsigned stackSize   = (G_PluginHost.getStack(pParent->stackType, pParent->ch))->size;
+
+       if (pluginIndex == stackSize-1)  // last one in the stack, do nothing
+               return;
+
+       G_PluginHost.swapPlugin(pluginIndex, pluginIndex+1, pParent->stackType, pParent->ch);
+       pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_removePlugin() {
+
+       /* os x hack: show window before deleting it */
+
+#ifdef __APPLE__
+       gdPluginWindowGUImac* w = (gdPluginWindowGUImac*) pParent->getChild(pPlugin->getId()+1);
+       if (w)
+               w->show();
+#endif
+
+       /* any subwindow linked to the plugin must be destroyed */
+
+       pParent->delSubWindow(pPlugin->getId()+1);
+       G_PluginHost.freePlugin(pPlugin->getId(), pParent->stackType, pParent->ch);
+       pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_openPluginWindow() {
+
+       /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved
+        * for the window 'add plugin'. */
+
+       /* TODO - at the moment you can open a window for each plugin in the stack.
+        * This is not consistent with the rest of the gui. You can avoid this by
+        * calling
+        *
+        * gu_openSubWindow(this, new gdPluginWindow(pPlugin), WID_FX);
+        *
+        * instead of the following code.
+        *
+        * EDIT 2 - having only 1 plugin window would be very uncomfortable */
+
+       if (!pParent->hasWindow(pPlugin->getId()+1)) {
+               gWindow *w;
+               if (pPlugin->hasGui())
+#ifdef __APPLE__
+                       w = new gdPluginWindowGUImac(pPlugin);
+#else
+                       w = new gdPluginWindowGUI(pPlugin);
+#endif
+               else
+                       w = new gdPluginWindow(pPlugin);
+               w->setId(pPlugin->getId()+1);
+               pParent->addSubWindow(w);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_setBypass() {
+       pPlugin->bypass = !pPlugin->bypass;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_setProgram() {
+       pPlugin->setProgram(program->value());
+}
+
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_pluginList.h b/src/gui/dialogs/gd_pluginList.h
new file mode 100644 (file)
index 0000000..5f96e89
--- /dev/null
@@ -0,0 +1,107 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginList
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+#ifndef __GD_PLUGINLIST_H__
+#define __GD_PLUGINLIST_H__
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include "../elems/ge_window.h"
+
+
+class gdPluginList : public gWindow {
+
+private:
+
+       class gClick *addPlugin;
+       Fl_Scroll    *list;
+
+       //gVector<class gdPluginWindow *> subWindows;
+
+       static void cb_addPlugin          (Fl_Widget *v, void *p);
+       inline void __cb_addPlugin        ();
+
+public:
+
+       class Channel *ch;      // ch == NULL ? masterOut
+       int   stackType;
+
+       gdPluginList(int stackType, class Channel *ch=NULL);
+       ~gdPluginList();
+
+       /* special callback, passed to browser. When closed (i.e. plugin
+        * has been selected) the same browser will refresh this window. */
+
+       static void cb_refreshList(Fl_Widget*, void*);
+
+       void refreshList();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdPlugin : public Fl_Group {
+
+private:
+
+       class  gdPluginList *pParent;
+       class  Plugin       *pPlugin;
+
+       static void cb_removePlugin       (Fl_Widget *v, void *p);
+       static void cb_openPluginWindow   (Fl_Widget *v, void *p);
+       static void cb_setBypass          (Fl_Widget *v, void *p);
+       static void cb_shiftUp            (Fl_Widget *v, void *p);
+       static void cb_shiftDown          (Fl_Widget *v, void *p);
+       static void cb_setProgram         (Fl_Widget *v, void *p);
+       inline void __cb_removePlugin     ();
+       inline void __cb_openPluginWindow ();
+       inline void __cb_setBypass        ();
+       inline void __cb_shiftUp          ();
+       inline void __cb_shiftDown        ();
+       inline void __cb_setProgram       ();
+
+public:
+
+       class gButton *button;
+       class gChoice *program;
+       class gButton *bypass;
+       class gButton *shiftUp;
+       class gButton *shiftDown;
+       class gButton *remove;
+
+       gdPlugin(gdPluginList *gdp, class Plugin *p, int x, int y, int w);
+
+};
+
+#endif
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_pluginWindow.cpp b/src/gui/dialogs/gd_pluginWindow.cpp
new file mode 100644 (file)
index 0000000..a60ebe5
--- /dev/null
@@ -0,0 +1,139 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginWindow
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+
+
+#include <FL/Fl_Scroll.H>
+#include "../../utils/gui_utils.h"
+#include "../../core/pluginHost.h"
+#include "../elems/ge_mixed.h"
+#include "gd_pluginWindow.h"
+
+
+
+extern PluginHost G_PluginHost;
+
+
+Parameter::Parameter(int id, Plugin *p, int X, int Y, int W)
+       : Fl_Group(X,Y,W-24,20), id(id), pPlugin(p)
+{
+       begin();
+
+               label = new gBox(x(), y(), 60, 20);
+               char name[kVstMaxParamStrLen];
+               pPlugin->getParamName(id, name);
+               label->copy_label(name);
+               label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+
+               slider = new gSlider(label->x()+label->w()+8, y(), W-200, 20);
+               slider->value(pPlugin->getParam(id));
+               slider->callback(cb_setValue, (void *)this);
+
+               value = new gBox(slider->x()+slider->w()+8, y(), 100, 20);
+               char disp[kVstMaxParamStrLen];
+               char labl[kVstMaxParamStrLen];
+               char str [256];
+               pPlugin->getParamDisplay(id, disp);
+               pPlugin->getParamLabel(id, labl);
+               sprintf(str, "%s %s", disp, labl);
+               value->copy_label(str);
+               value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+               value->box(G_BOX);
+
+               resizable(slider);
+
+       end();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Parameter::cb_setValue(Fl_Widget *v, void *p)  { ((Parameter*)p)->__cb_setValue(); }
+
+
+/* ------------------------------------------------------------------ */
+
+
+void Parameter::__cb_setValue() {
+
+       pPlugin->setParam(id, slider->value());
+
+       char disp[256];
+       char labl[256];
+       char str [256];
+
+       pPlugin->getParamDisplay(id, disp);
+       pPlugin->getParamLabel(id, labl);
+       sprintf(str, "%s %s", disp, labl);
+
+       value->copy_label(str);
+       value->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdPluginWindow::gdPluginWindow(Plugin *pPlugin)
+ : gWindow(400, 156), pPlugin(pPlugin) // 350
+{
+       set_non_modal();
+
+       gLiquidScroll *list = new gLiquidScroll(8, 8, w()-16, h()-16);
+       list->type(Fl_Scroll::VERTICAL_ALWAYS);
+       list->begin();
+
+       int numParams = pPlugin->getNumParams();
+       for (int i=0; i<numParams; i++)
+               new Parameter(i, pPlugin, list->x(), list->y()+(i*24), list->w());
+       list->end();
+
+       end();
+
+       char name[256];
+       pPlugin->getProduct(name);
+       if (strcmp(name, " ")==0)
+               pPlugin->getName(name);
+       label(name);
+
+       size_range(400, (24*1)+12);
+       resizable(list);
+
+       gu_setFavicon(this);
+       show();
+
+}
+
+
+gdPluginWindow::~gdPluginWindow() {}
+
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_pluginWindow.h b/src/gui/dialogs/gd_pluginWindow.h
new file mode 100644 (file)
index 0000000..0f50529
--- /dev/null
@@ -0,0 +1,76 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginWindow
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifdef WITH_VST
+
+#ifndef __GD_PLUGINWINDOW_H__
+#define __GD_PLUGINWINDOW_H__
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../elems/ge_window.h"
+
+
+class gdPluginWindow : public gWindow {
+
+private:
+       class Plugin *pPlugin;
+
+public:
+       int id;
+
+       gdPluginWindow(Plugin *pPlugin);
+       ~gdPluginWindow();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class Parameter : public Fl_Group {
+
+private:
+       int   id;
+       class Plugin *pPlugin;
+
+       static void cb_setValue(Fl_Widget *v, void *p);
+       inline void __cb_setValue();
+
+public:
+       class gBox    *label;
+       class gSlider *slider;
+       class gBox    *value;
+
+       Parameter(int id, class Plugin *p, int x, int y, int w);
+};
+
+
+#endif
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_pluginWindowGUI.cpp b/src/gui/dialogs/gd_pluginWindowGUI.cpp
new file mode 100644 (file)
index 0000000..7b6ff31
--- /dev/null
@@ -0,0 +1,199 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginWindowGUI
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+
+
+#include "../../utils/log.h"
+#include "../../utils/gui_utils.h"
+#include "../../core/pluginHost.h"
+#include "../elems/ge_mixed.h"
+#include "gd_pluginWindowGUI.h"
+
+
+extern PluginHost G_PluginHost;
+
+
+gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
+ : gWindow(450, 300), pPlugin(pPlugin)
+{
+
+  /* some effects like to have us get their rect before opening them */
+
+  ERect *rect;
+       pPlugin->getRect(&rect);
+
+       gu_setFavicon(this);
+       set_non_modal();
+       resize(x(), y(), pPlugin->getGuiWidth(), pPlugin->getGuiWidth());
+       show();
+
+  gLog("[gdPluginWindowGUI] open window, w=%d h=%d\n",
+      pPlugin->getGuiWidth(), pPlugin->getGuiWidth());
+
+       /* Fl::check(): Waits until "something happens" and then returns. It's
+        * mandatory on linux, otherwise X can't find 'this' window. */
+
+#ifndef __APPLE__
+       Fl::check();
+#endif
+
+       pPlugin->openGui((void*)fl_xid(this));
+
+       char name[256];
+       pPlugin->getProduct(name);
+       copy_label(name);
+
+       /* add a pointer to this window to plugin */
+
+       pPlugin->window = this;
+
+       pPlugin->idle();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdPluginWindowGUI::~gdPluginWindowGUI() {
+       pPlugin->closeGui();
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+#if defined(__APPLE__)
+
+
+pascal OSStatus gdPluginWindowGUImac::windowHandler(EventHandlerCallRef ehc, EventRef e, void *data) {
+       return ((gdPluginWindowGUImac*)data)->__wh(ehc, e);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+pascal OSStatus gdPluginWindowGUImac::__wh(EventHandlerCallRef inHandlerCallRef, EventRef inEvent) {
+       OSStatus result   = eventNotHandledErr;     // let the Carbon Event Manager close the window
+       UInt32 eventClass = GetEventClass(inEvent);
+       UInt32 eventKind  = GetEventKind(inEvent);
+
+       switch (eventClass)     {
+               case kEventClassWindow: {
+                       switch (eventKind) {
+                               case kEventWindowClose: {
+                                       gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClose for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow);
+                                       show();
+                                       break;
+                               }
+                               case kEventWindowClosed: {
+                                       gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClosed for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow);
+                                       open = false;
+                                       result = noErr;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
+       return result;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdPluginWindowGUImac::gdPluginWindowGUImac(Plugin *pPlugin)
+ : gWindow(450, 300), pPlugin(pPlugin), carbonWindow(NULL)
+{
+
+  /* some effects like to have us get their rect before opening them */
+
+  ERect *rect;
+       pPlugin->getRect(&rect);
+
+       /* window initialization */
+
+       Rect wRect;
+
+       wRect.top    = rect->top;
+       wRect.left   = rect->left;
+       wRect.bottom = rect->bottom;
+       wRect.right  = rect->right;
+
+  int winclass = kDocumentWindowClass;
+  int winattr  = kWindowStandardHandlerAttribute |
+                 kWindowCloseBoxAttribute        |
+                 kWindowCompositingAttribute     |
+                 kWindowAsyncDragAttribute;
+
+  // winattr &= GetAvailableWindowAttributes(winclass);        // make sure that the window will open
+
+  OSStatus status = CreateNewWindow(winclass, winattr, &wRect, &carbonWindow);
+       if (status != noErr)    {
+               gLog("[pluginWindowMac] Unable to create window! Status=%d\n", (int) status);
+               return;
+       }
+       else
+               gLog("[pluginWindowMac] created window=%p\n", (void*)carbonWindow);
+
+       /* install event handler, called when window is closed */
+
+       static EventTypeSpec eventTypes[] = {
+               { kEventClassWindow, kEventWindowClose },
+               { kEventClassWindow, kEventWindowClosed }
+       };
+       InstallWindowEventHandler(carbonWindow, windowHandler, GetEventTypeCount(eventTypes), eventTypes, this, NULL);
+
+       /* open window, center it, show it and start the handler */
+
+       pPlugin->openGui((void*)carbonWindow);
+       RepositionWindow(carbonWindow, NULL, kWindowCenterOnMainScreen);
+       ShowWindow(carbonWindow);
+       open = true;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+
+
+gdPluginWindowGUImac::~gdPluginWindowGUImac() {
+       gLog("[pluginWindowMac] [[[ destructor ]]] gWindow=%p deleted, window=%p deleted\n", (void*)this, (void*)carbonWindow);
+       pPlugin->closeGui();
+       if (open)
+               DisposeWindow(carbonWindow);
+}
+
+#endif
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_pluginWindowGUI.h b/src/gui/dialogs/gd_pluginWindowGUI.h
new file mode 100644 (file)
index 0000000..516b879
--- /dev/null
@@ -0,0 +1,84 @@
+
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginWindowGUI
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifdef WITH_VST
+
+
+#ifndef __GD_PLUGINWINDOW_GUI_H__
+#define __GD_PLUGINWINDOW_GUI_H__
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../elems/ge_window.h"
+#if defined(__APPLE__)
+       #include <Carbon/Carbon.h>
+#endif
+
+
+class gdPluginWindowGUI : public gWindow {
+private:
+
+       class Plugin *pPlugin;
+
+public:
+
+       gdPluginWindowGUI(Plugin *pPlugin);
+       ~gdPluginWindowGUI();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+#if defined(__APPLE__)
+
+class gdPluginWindowGUImac : public gWindow {
+
+private:
+
+       static pascal OSStatus windowHandler(EventHandlerCallRef ehc, EventRef e, void *data);
+       inline pascal OSStatus __wh(EventHandlerCallRef ehc, EventRef e);
+
+       class Plugin *pPlugin;
+       WindowRef carbonWindow;
+       bool open;
+
+public:
+
+       gdPluginWindowGUImac(Plugin *pPlugin);
+       ~gdPluginWindowGUImac();
+};
+
+#endif
+
+
+#endif // include guard
+
+#endif // #ifdef WITH_VST
diff --git a/src/gui/dialogs/gd_warnings.cpp b/src/gui/dialogs/gd_warnings.cpp
new file mode 100644 (file)
index 0000000..31a5dbc
--- /dev/null
@@ -0,0 +1,78 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_warnings
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "gd_warnings.h"
+
+
+void gdAlert(const char *c) {
+       Fl_Window *modal = new Fl_Window(
+                       (Fl::w() / 2) - 150,
+                       (Fl::h() / 2) - 47,
+                       300, 90, "Alert");
+       modal->set_modal();
+       modal->begin();
+               gBox *box = new gBox(10, 10, 280, 40, c);
+               gClick *b = new gClick(210, 60, 80, 20, "Close");
+       modal->end();
+       box->labelsize(11);
+       b->callback(__cb_window_closer, (void *)modal);
+       b->shortcut(FL_Enter);
+       gu_setFavicon(modal);
+       modal->show();
+}
+
+
+int gdConfirmWin(const char *title, const char *msg) {
+       Fl_Window *win = new Fl_Window(
+                       (Fl::w() / 2) - 150,
+                       (Fl::h() / 2) - 47,
+                       300, 90, title);
+       win->set_modal();
+       win->begin();
+               new gBox(10, 10, 280, 40, msg);
+               gClick *ok = new gClick(212, 62, 80, 20, "Ok");
+               gClick *ko = new gClick(124, 62, 80, 20, "Cancel");
+       win->end();
+       ok->shortcut(FL_Enter);
+       gu_setFavicon(win);
+       win->show();
+
+       /* no callbacks here. readqueue() check the event stack. */
+
+       int r = 0;
+       while (true) {
+               Fl_Widget *o = Fl::readqueue();
+               if (!o) Fl::wait();
+               else if (o == ok) {r = 1; break;}
+               else if (o == ko) {r = 0; break;}
+       }
+       //delete win;
+       win->hide();
+       return r;
+}
diff --git a/src/gui/dialogs/gd_warnings.h b/src/gui/dialogs/gd_warnings.h
new file mode 100644 (file)
index 0000000..791d236
--- /dev/null
@@ -0,0 +1,43 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_warnings
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GD_WARNINGS_H
+#define GD_WARNINGS_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Box.H>
+#include "../elems/ge_mixed.h"
+#include "../../utils/gui_utils.h"
+
+
+void gdAlert(const char *c);
+
+int  gdConfirmWin(const char *title, const char *msg);
+
+#endif
diff --git a/src/gui/elems/ge_actionChannel.cpp b/src/gui/elems/ge_actionChannel.cpp
new file mode 100644 (file)
index 0000000..b744ac3
--- /dev/null
@@ -0,0 +1,676 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionChannel
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "ge_keyboard.h"
+#include "ge_actionChannel.h"
+
+
+extern gdMainWindow *mainWin;
+extern Mixer         G_Mixer;
+extern Conf             G_Conf;
+
+
+/* ------------------------------------------------------------------ */
+
+
+gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch)
+ : gActionWidget(x, y, 200, 40, pParent), ch(ch), selected(NULL)
+{
+       size(pParent->totalWidth, h());
+
+       /* add actions when the window opens. Their position is zoom-based;
+        * each frame is / 2 because we don't care about stereo infos. */
+
+       for (unsigned i=0; i<recorder::frames.size; i++) {
+               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
+
+                       recorder::action *ra = recorder::global.at(i).at(j);
+
+                       if (ra->chan == pParent->chan->index) {
+
+                               /* don't show actions > than the grey area */
+
+                               if (recorder::frames.at(i) > G_Mixer.totalFrames)
+                                       continue;
+
+                               /* skip the killchan actions in a singlepress channel. They cannot be recorded
+                                * in such mode, but they can exist if you change from another mode to singlepress */
+
+                               if (ra->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS)
+                                       continue;
+
+                               /* also filter out ACTION_KEYREL: it's up to gAction to find the other piece
+                                * (namely frame_b) */
+
+                               if (ra->type & (ACTION_KEYPRESS | ACTION_KILLCHAN))     {
+                                       int ax = x+(ra->frame/pParent->zoom);
+                                       gAction *a = new gAction(
+                                                       ax,           // x
+                                                       y+4,          // y
+                                                       h()-8,        // h
+                                                       ra->frame,        // frame_a
+                                                       i,            // n. of recordings
+                                                       pParent,      // pointer to the pParent window
+                                                       ch,           // pointer to SampleChannel
+                                                       false,        // record = false: don't record it, we are just displaying it!
+                                                       ra->type);    // type of action
+                                       add(a);
+                               }
+                       }
+               }
+       }
+       end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gAction *gActionChannel::getSelectedAction() {
+       for (int i=0; i<children(); i++) {
+               int action_x  = ((gAction*)child(i))->x();
+               int action_w  = ((gAction*)child(i))->w();
+               if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w)
+                       return (gAction*)child(i);
+       }
+       return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gActionChannel::updateActions() {
+
+       /* when zooming, don't delete and re-add actions, just MOVE them. This
+        * function shifts the action by a zoom factor. Those singlepress are
+        * stretched, as well */
+
+       gAction *a;
+       for (int i=0; i<children(); i++) {
+
+               a = (gAction*)child(i);
+               int newX = x() + (a->frame_a / pParent->zoom);
+
+               if (ch->mode == SINGLE_PRESS) {
+                       int newW = ((a->frame_b - a->frame_a) / pParent->zoom);
+                       if (newW < gAction::MIN_WIDTH)
+                               newW = gAction::MIN_WIDTH;
+                       a->resize(newX, a->y(), newW, a->h());
+               }
+               else
+                       a->resize(newX, a->y(), gAction::MIN_WIDTH, a->h());
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gActionChannel::draw() {
+
+       /* draw basic boundaries (+ beat bars) and hide the unused area. Then
+        * draw the children (the actions) */
+
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       if (active())
+               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
+       else
+               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
+
+       draw_children();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gActionChannel::handle(int e) {
+
+       int ret = Fl_Group::handle(e);
+
+       /* do nothing if the widget is deactivated. It could happen for loopmode
+        * channels */
+
+       if (!active())
+               return 1;
+
+       switch (e) {
+
+               case FL_DRAG: {
+                       if (selected != NULL) {   // if you don't drag an empty area
+
+                               /* if onLeftEdge o onRightEdge are true it means that you're resizing
+                                * an action. Otherwise move the widget. */
+
+                               if (selected->onLeftEdge || selected->onRightEdge) {
+
+                                       /* some checks: a) cannot resize an action < N pixels, b) no beyond zero,
+                                        * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */
+
+                                       if (selected->onRightEdge) {
+
+                                               int aw = Fl::event_x()-selected->x();
+                                               int ah = selected->h();
+
+                                               if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH)
+                                                       aw = gAction::MIN_WIDTH;
+                                               else
+                                               if (Fl::event_x() > pParent->coverX)
+                                                       aw = pParent->coverX-selected->x();
+
+                                               selected->size(aw, ah);
+                                       }
+                                       else {
+
+                                               int ax = Fl::event_x();
+                                               int ay = selected->y();
+                                               int aw = selected->x()-Fl::event_x()+selected->w();
+                                               int ah = selected->h();
+
+                                               if (Fl::event_x() < x()) {
+                                                       ax = x();
+                                                       aw = selected->w()+selected->x()-x();
+                                               }
+                                               else
+                                               if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) {
+                                                       ax = selected->x()+selected->w()-gAction::MIN_WIDTH;
+                                                       aw = gAction::MIN_WIDTH;
+                                               }
+                                               selected->resize(ax, ay, aw, ah);
+                                       }
+                               }
+
+                               /* move the widget around */
+
+                               else {
+                                       int real_x = Fl::event_x() - actionPickPoint;
+                                       if (real_x < x())                                  // don't go beyond the left border
+                                               selected->position(x(), selected->y());
+                                       else
+                                       if (real_x+selected->w() > pParent->coverX+x())         // don't go beyond the right border
+                                               selected->position(pParent->coverX+x()-selected->w(), selected->y());
+                                       else {
+                                               if (pParent->gridTool->isOn()) {
+                                                       int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1;
+                                                       selected->position(snpx, selected->y());
+                                               }
+                                               else
+                                                       selected->position(real_x, selected->y());
+                                       }
+                               }
+                               redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH:   {
+
+                       if (Fl::event_button1()) {
+
+                               /* avoid at all costs two overlapping actions. We use 'selected' because
+                                * the selected action can be reused in FL_DRAG, in case you want to move
+                                * it. */
+
+                               selected = getSelectedAction();
+
+                               if (selected == NULL) {
+
+                                       /* avoid click on grey area */
+
+                                       if (Fl::event_x() >= pParent->coverX) {
+                                               ret = 1;
+                                               break;
+                                       }
+
+                                       /* snap function, if enabled */
+
+                                       int ax = Fl::event_x();
+                                       int fx = (ax - x()) * pParent->zoom;
+                                       if (pParent->gridTool->isOn()) {
+                                               ax = pParent->gridTool->getSnapPoint(ax-x()) + x() -1;
+                                               fx = pParent->gridTool->getSnapFrame(ax-x());
+
+                                               /* with snap=on an action can fall onto another */
+
+                                               if (actionCollides(fx)) {
+                                                       ret = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       gAction *a = new gAction(
+                                                       ax,                                   // x
+                                                       y()+4,                                // y
+                                                       h()-8,                                // h
+                                                       fx,                                                                                                                                             // frame_a
+                                                       recorder::frames.size-1,              // n. of actions recorded
+                                                       pParent,                              // pParent window pointer
+                                                       ch,                                   // pointer to SampleChannel
+                                                       true,                                 // record = true: record it!
+                                                       pParent->getActionType());            // type of action
+                                       add(a);
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); // mainWindow update
+                                       redraw();
+                                       ret = 1;
+                               }
+                               else {
+                                       actionOriginalX = selected->x();
+                                       actionOriginalW = selected->w();
+                                       actionPickPoint = Fl::event_x() - selected->x();
+                                       ret = 1;   // for dragging
+                               }
+                       }
+                       else
+                       if (Fl::event_button3()) {
+                               gAction *a = getSelectedAction();
+                               if (a != NULL) {
+                                       a->delAction();
+                                       remove(a);
+                                       delete a;
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel);
+                                       redraw();
+                                       ret = 1;
+                               }
+                       }
+                       break;
+               }
+               case FL_RELEASE: {
+
+                       if (selected == NULL) {
+                               ret = 1;
+                               break;
+                       }
+
+                       /* noChanges = true when you click on an action without doing anything
+                        * (dragging or moving it). */
+
+                       bool noChanges = false;
+                       if (actionOriginalX == selected->x())
+                               noChanges = true;
+                       if (ch->mode == SINGLE_PRESS &&
+                                       actionOriginalX+actionOriginalW != selected->x()+selected->w())
+                               noChanges = false;
+
+                       if (noChanges) {
+                               ret = 1;
+                               selected = NULL;
+                               break;
+                       }
+
+                       /* step 1: check if the action doesn't overlap with another one.
+                        * In case of overlap the moved action returns to the original X
+                        * value ("actionOriginalX"). */
+
+                       bool overlap = false;
+                       for (int i=0; i<children() && !overlap; i++) {
+
+                               /* never check against itself. */
+
+                               if ((gAction*)child(i) == selected)
+                                       continue;
+
+                               int action_x  = ((gAction*)child(i))->x();
+                               int action_w  = ((gAction*)child(i))->w();
+                               if (ch->mode == SINGLE_PRESS) {
+
+                                       /* when 2 segments overlap?
+                                        * start = the highest value between the two starting points
+                                        * end   = the lowest value between the two ending points
+                                        * if start < end then there's an overlap of end-start pixels. */
+
+                                        int start = action_x >= selected->x() ? action_x : selected->x();
+                                        int end   = action_x+action_w < selected->x()+selected->w() ? action_x+action_w : selected->x()+selected->w();
+                                        if (start < end) {
+                                               selected->resize(actionOriginalX, selected->y(), actionOriginalW, selected->h());
+                                               redraw();
+                                               overlap = true;   // one overlap: stop checking
+                                       }
+                               }
+                               else {
+                                       if (selected->x() == action_x) {
+                                               selected->position(actionOriginalX, selected->y());
+                                               redraw();
+                                               overlap = true;   // one overlap: stop checking
+                                       }
+                               }
+                       }
+
+                       /* step 2: no overlap? then update the coordinates of the action, ie
+                        * delete the previous rec and create a new one.
+                        * Anyway the selected action becomes NULL, because when you release
+                        * the mouse button the dragging process ends. */
+
+                       if (!overlap) {
+                               if (pParent->gridTool->isOn()) {
+                                       int f = pParent->gridTool->getSnapFrame(selected->absx());
+                                       selected->moveAction(f);
+                               }
+                               else
+                                       selected->moveAction();
+                       }
+                       selected = NULL;
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gActionChannel::actionCollides(int frame) {
+
+       /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't
+        * overlap the head (frame) of the new one. First the general case, yet. */
+
+       bool collision = false;
+
+       for (int i=0; i<children() && !collision; i++)
+               if ( ((gAction*)child(i))->frame_a == frame)
+                       collision = true;
+
+       if (ch->mode == SINGLE_PRESS) {
+               for (int i=0; i<children() && !collision; i++) {
+                       gAction *c = ((gAction*)child(i));
+                       if (frame <= c->frame_b && frame >= c->frame_a)
+                               collision = true;
+               }
+       }
+
+       return collision;
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+const int gAction::MIN_WIDTH = 8;
+
+
+/* ------------------------------------------------------------------ */
+
+
+/** TODO - index is useless?
+ *  TODO - pass a record::action pointer and let gAction compute values */
+
+gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEditor *parent, SampleChannel *ch, bool record, char type)
+: Fl_Box     (X, Y, MIN_WIDTH, H),
+  selected   (false),
+  index      (index),
+  parent     (parent),
+  ch         (ch),
+  type       (type),
+  frame_a    (frame_a),
+  onRightEdge(false),
+  onLeftEdge (false)
+{
+       /* bool 'record' defines how to understand the action.
+        * record = false: don't record it, just show it. It happens when you
+        * open the editor with some actions to be shown.
+        *
+        * record = true: record it AND show it. It happens when you click on
+        * an empty area in order to add a new actions. First you record it
+        * (addAction()) then you show it (FLTK::Draw()) */
+
+       if (record)
+               addAction();
+
+       /* in order to show a singlepress action we must compute the frame_b. We
+        * do that after the possible recording, otherwise we don't know which
+        * key_release is associated. */
+
+       if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) {
+               recorder::action *a2 = NULL;
+               recorder::getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2);
+               if (a2) {
+                       frame_b = a2->frame;
+                       w((frame_b - frame_a)/parent->zoom);
+               }
+               else
+                       gLog("[gActionChannel] frame_b not found! [%d:???]\n", frame_a);
+
+       /* a singlepress action narrower than 8 pixel is useless. So check it.
+        * Warning: if an action is 8 px narrow, it has no body space to drag
+        * it. It's up to the user to zoom in and drag it. */
+
+               if (w() < MIN_WIDTH)
+                       size(MIN_WIDTH, h());
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gAction::draw() {
+
+       int color;
+       if (selected)  /// && gActionChannel !disabled
+               color = COLOR_BD_1;
+       else
+               color = COLOR_BG_2;
+
+       if (ch->mode == SINGLE_PRESS) {
+               fl_rectf(x(), y(), w(), h(), (Fl_Color) color);
+       }
+       else {
+               if (type == ACTION_KILLCHAN)
+                       fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
+               else {
+                       fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
+                       if (type == ACTION_KEYPRESS)
+                               fl_rectf(x()+3, y()+h()-11, 2, 8, COLOR_BD_0);
+                       else
+                       if  (type == ACTION_KEYREL)
+                               fl_rectf(x()+3, y()+3, 2, 8, COLOR_BD_0);
+               }
+       }
+
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gAction::handle(int e) {
+
+       /* ret = 0 sends the event to the parent window. */
+
+       int ret = 0;
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       selected = true;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+               case FL_LEAVE: {
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       selected = false;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+               case FL_MOVE: {
+
+                       /* handling of the two margins, left & right. 4 pixels are good enough */
+
+                       if (ch->mode == SINGLE_PRESS) {
+                               onLeftEdge  = false;
+                               onRightEdge = false;
+                               if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
+                                       onLeftEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                               if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
+                                       onRightEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       }
+               }
+       }
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gAction::addAction() {
+
+       /* always check frame parity */
+
+       if (frame_a % 2 != 0)
+               frame_a++;
+
+       /* anatomy of an action
+        * ____[#######]_____ (a) is the left margin, ACTION_KEYPRESS. (b) is
+        *     a       b      the right margin, the ACTION_KEYREL. This is the
+        * theory behind the singleshot.press actions; for any other kind the
+        * (b) is just a graphical and meaningless point. */
+
+       if (ch->mode == SINGLE_PRESS) {
+               recorder::rec(parent->chan->index, ACTION_KEYPRESS, frame_a);
+               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_a+4096);
+               //gLog("action added, [%d, %d]\n", frame_a, frame_a+4096);
+       }
+       else {
+               recorder::rec(parent->chan->index, parent->getActionType(), frame_a);
+               //gLog("action added, [%d]\n", frame_a);
+       }
+
+       recorder::sortActions();
+
+       index++; // important!
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gAction::delAction() {
+
+       /* if SINGLE_PRESS you must delete both the keypress and the keyrelease
+        * actions. */
+
+       if (ch->mode == SINGLE_PRESS) {
+               recorder::deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false);
+               recorder::deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false);
+       }
+       else
+               recorder::deleteAction(parent->chan->index, frame_a, type, false);
+
+       /* restore the initial cursor shape, in case you delete an action and
+        * the double arrow (for resizing) is displayed */
+
+       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gAction::moveAction(int frame_a) {
+
+       /* easy one: delete previous action and record the new ones. As usual,
+        * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame
+        * value. */
+
+       delAction();
+
+       if (frame_a != -1)
+               this->frame_a = frame_a;
+       else
+               this->frame_a = xToFrame_a();
+
+
+       /* always check frame parity */
+
+       if (this->frame_a % 2 != 0)
+               this->frame_a++;
+
+       recorder::rec(parent->chan->index, type, this->frame_a);
+
+       if (ch->mode == SINGLE_PRESS) {
+               frame_b = xToFrame_b();
+               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_b);
+       }
+
+       recorder::sortActions();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gAction::absx() {
+       return x() - parent->ac->x();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gAction::xToFrame_a() {
+       return (absx()) * parent->zoom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gAction::xToFrame_b() {
+       return (absx() + w()) * parent->zoom;
+}
diff --git a/src/gui/elems/ge_actionChannel.h b/src/gui/elems/ge_actionChannel.h
new file mode 100644 (file)
index 0000000..67413fd
--- /dev/null
@@ -0,0 +1,135 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionChannel
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GE_ACTIONCHANNEL_H
+#define GE_ACTIONCHANNEL_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Box.H>
+#include "../../utils/gui_utils.h"
+#include "../../core/mixer.h"
+#include "../../core/recorder.h"
+#include "ge_actionWidget.h"
+
+
+class gAction : public Fl_Box {
+
+private:
+
+       bool                  selected;
+       unsigned              index;
+  class gdActionEditor *parent;   // pointer to parent (gActionEditor)
+       class SampleChannel  *ch;
+  char                  type;     // type of action
+
+public:
+       gAction(int x, int y, int h, int frame_a, unsigned index,
+                                 gdActionEditor *parent, class SampleChannel *ch, bool record,
+                           char type);
+       void draw();
+       int  handle(int e);
+       void addAction();
+       void delAction();
+
+       /* moveAction
+        * shift the action on the x-axis and update Recorder. If frame_a != -1
+        * use the new frame in input (used while snapping) */
+
+       void moveAction(int frame_a=-1);
+
+       /* absx
+        * x() is relative to scrolling position. absx() returns the absolute
+        * x value of the action, from the leftmost edge. */
+
+       int  absx();
+
+       /* xToFrame_a,b
+        * return the real frames of x() position */
+
+       int xToFrame_a();
+       int xToFrame_b();
+
+       int frame_a;  // initial frame (KEYPRESS for singlemode.press)
+       int frame_b;  // terminal frame (KEYREL for singlemode.press, null for others)
+
+       bool onRightEdge;
+       bool onLeftEdge;
+
+       static const int MIN_WIDTH;
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gActionChannel : public gActionWidget {
+
+private:
+
+       class SampleChannel *ch;
+
+       /* getSelectedAction
+        * get the action under the mouse. NULL if nothing found. */
+
+       gAction *getSelectedAction();
+
+       /* selected
+        * pointer to the selected action. Useful when dragging around. */
+
+       gAction *selected;
+
+       /* actionOriginalX, actionOriginalW
+        * x and w of the action, when moved. Useful for checking if the action
+        * overlaps another one: in that case the moved action returns to
+        * actionOriginalX (and to actionOriginalW if resized). */
+
+       int actionOriginalX;
+       int actionOriginalW;
+
+       /* actionPickPoint
+        * the precise x point in which the action has been picked with the mouse,
+        * before a dragging action. */
+
+       int actionPickPoint;
+
+
+       /* actionCollides
+        * true if an action collides with another. Used while adding new points
+        * with snap active.*/
+
+       bool actionCollides(int frame);
+
+public:
+       gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch);
+       void draw();
+       int  handle(int e);
+       void updateActions();
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_actionWidget.cpp b/src/gui/elems/ge_actionWidget.cpp
new file mode 100644 (file)
index 0000000..05b4db0
--- /dev/null
@@ -0,0 +1,101 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionWidget
+ *
+ * pParent class of any widget inside the action editor.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/mixer.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "ge_actionWidget.h"
+#include "ge_mixed.h"
+
+
+extern Mixer G_Mixer;
+
+
+gActionWidget::gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent)
+       :       Fl_Group(x, y, w, h), pParent(pParent) {}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gActionWidget::~gActionWidget() {}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gActionWidget::baseDraw(bool clear) {
+
+       /* clear the screen */
+
+       if (clear)
+               fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
+
+       /* draw the container */
+
+       fl_color(COLOR_BD_0);
+       fl_rect(x(), y(), w(), h());
+
+       /* grid drawing, if > 1 */
+
+       if (pParent->gridTool->getValue() > 1) {
+
+               fl_color(fl_rgb_color(54, 54, 54));
+               fl_line_style(FL_DASH, 0, NULL);
+
+               for (int i=0; i<(int) pParent->gridTool->points.size; i++) {
+                       int px = pParent->gridTool->points.at(i)+x()-1;
+                       fl_line(px, y()+1, px, y()+h()-2);
+               }
+               fl_line_style(0);
+       }
+
+       /* bars and beats drawing */
+
+       fl_color(COLOR_BD_0);
+       for (int i=0; i<(int) pParent->gridTool->beats.size; i++) {
+               int px = pParent->gridTool->beats.at(i)+x()-1;
+               fl_line(px, y()+1, px, y()+h()-2);
+       }
+
+       fl_color(COLOR_BG_2);
+       for (int i=0; i<(int) pParent->gridTool->bars.size; i++) {
+               int px = pParent->gridTool->bars.at(i)+x()-1;
+               fl_line(px, y()+1, px, y()+h()-2);
+       }
+
+       /* cover unused area. Avoid drawing cover if width == 0 (i.e. beats
+        * are 32) */
+
+       int coverWidth = pParent->totalWidth-pParent->coverX;
+       if (coverWidth != 0)
+               fl_rectf(pParent->coverX+x(), y()+1, coverWidth, h()-2, COLOR_BG_1);
+}
diff --git a/src/gui/elems/ge_actionWidget.h b/src/gui/elems/ge_actionWidget.h
new file mode 100644 (file)
index 0000000..b02f8d7
--- /dev/null
@@ -0,0 +1,53 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionWidget
+ *
+ * parent class of any widget inside the action editor.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef __GE_ACTIONWIDGET_H__
+#define __GE_ACTIONWIDGET_H__
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "../../core/const.h"
+
+
+class gActionWidget : public Fl_Group {
+
+protected:
+       class gdActionEditor *pParent;
+       void  baseDraw(bool clear=true);
+
+public:
+       virtual void updateActions() = 0;
+
+       gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent);
+       ~gActionWidget();
+};
+
+#endif
diff --git a/src/gui/elems/ge_browser.cpp b/src/gui/elems/ge_browser.cpp
new file mode 100644 (file)
index 0000000..fd70dcc
--- /dev/null
@@ -0,0 +1,307 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_browser
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <limits.h>
+#include "../../core/const.h"
+#include "../../utils/utils.h"
+#include "../../utils/log.h"
+#include "ge_browser.h"
+
+
+gBrowser::gBrowser(int x, int y, int w, int h, const char *L)
+ : Fl_Hold_Browser(x, y, w, h, L)
+{
+       box(G_BOX);
+       textsize(11);
+       textcolor(COLOR_TEXT_0);
+       selection_color(COLOR_BG_1);
+       color(COLOR_BG_0);
+
+       this->scrollbar.color(COLOR_BG_0);
+       this->scrollbar.selection_color(COLOR_BG_1);
+       this->scrollbar.labelcolor(COLOR_BD_1);
+       this->scrollbar.slider(G_BOX);
+
+       this->hscrollbar.color(COLOR_BG_0);
+       this->hscrollbar.selection_color(COLOR_BG_1);
+       this->hscrollbar.labelcolor(COLOR_BD_1);
+       this->hscrollbar.slider(G_BOX);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gBrowser::~gBrowser() {}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gBrowser::init(const char *init_path) {
+
+       gLog("[gBrowser] init path = '%s'\n", init_path);
+
+       if (init_path == NULL || !gIsDir(init_path)) {
+#if defined(__linux__) || defined(__APPLE__)
+               path_obj->value("/home");
+#elif defined(_WIN32)
+
+               /* SHGetFolderPath is deprecated. We should use SHGetKnownFolderPath
+                * but that would break compatibility with XP. On Vista, GetFolderPath
+                * is a wrapper of GetKnownFolderPath, so no problem. */
+
+               char winRoot[1024];
+               SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, winRoot); // si parte dal Desktop
+               path_obj->value(winRoot);
+#endif
+               gLog("[gBrowser] init_path null or invalid, using default\n");
+       }
+       else
+               path_obj->value(init_path);
+
+       refresh();
+       sort();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gBrowser::refresh() {
+  DIR *dp;
+  struct dirent *ep;
+  dp = opendir(path_obj->value());
+  if (dp != NULL) {
+               while ((ep = readdir(dp))) {
+
+                       /* skip:
+                        * - "." e ".."
+                        * - hidden files */
+
+                       if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
+                               if (ep->d_name[0] != '.') {
+
+                                       /* is it a folder? add square brackets. Is it a file? Append
+                                        * a '/' (on Windows seems useless, though) */
+
+                                       std::string file = path_obj->value();
+                                       file.insert(file.size(), gGetSlash());
+                                       file += ep->d_name;
+
+                                       if (gIsDir(file.c_str())) {
+                                               char name[PATH_MAX];
+                                               sprintf(name, "@b[%s]", ep->d_name);
+                                               add(name);
+                                       }
+                                       else
+                                       if (gIsProject(file.c_str())) {
+                                               char name[PATH_MAX];
+                                               sprintf(name, "@i@b%s", ep->d_name);
+                                               add(name);
+                                       }
+                                       else
+                                               add(ep->d_name);
+                               }
+                       }
+               }
+               closedir(dp);
+  }
+  else
+    gLog("[gBrowser] Couldn't open the directory '%s'\n", path_obj->value());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gBrowser::sort() {
+       for (int t=1; t<=size(); t++)
+               for (int r=t+1; r<=size(); r++)
+                       if (strcmp(text(t), text(r)) > 0)
+                               swap(t,r);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gBrowser::up_dir() {
+
+       /* updir = remove last folder from the path. Start from strlen(-1) to
+        * skip the trailing slash */
+
+       int i = strlen(path_obj->value())-1;
+
+       /* on Windows an updir from the path "X:\" (3 chars long) must redirect
+        * to the list of available devices. */
+
+#if defined(_WIN32)
+       if (i <= 3 || !strcmp(path_obj->value(), "All drives")) {
+               path_obj->value("All drives");
+               showDrives();
+               return;
+       }
+       else {
+               while (i >= 0) {
+                       if (path_obj->value()[i] == '\\')
+                               break;
+                       i--;
+               }
+
+               /* delete the last part of the string, from i to len-i, ie everything
+                * after the "/" */
+
+               std::string tmp = path_obj->value();
+               tmp.erase(i, tmp.size()-i);
+
+               /* if tmp.size == 2 we have something like 'C:'. Add a trailing
+                * slash */
+
+               if (tmp.size() == 2)
+                       tmp += "\\";
+
+               path_obj->value(tmp.c_str());
+               refresh();
+       }
+#elif defined(__linux__) || defined (__APPLE__)
+       while (i >= 0) {
+               if (path_obj->value()[i] == '/')
+                       break;
+               i--;
+       }
+
+       /* i == 0 means '/', the root dir. It's meaningless to go updir */
+
+       if (i==0)
+               path_obj->value("/");
+       else {
+
+               /* delete the last part of the string, from i to len-i, ie everything
+                * after the "/" */
+
+               std::string tmp = path_obj->value();
+               tmp.erase(i, tmp.size()-i);
+               path_obj->value(tmp.c_str());
+       }
+       refresh();
+#endif
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gBrowser::down_dir(const char *path) {
+       path_obj->value(path);
+       refresh();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+const char *gBrowser::get_selected_item() {
+
+       /* click on an empty line */
+
+       if (text(value()) == NULL)
+               return NULL;
+
+       selected_item = text(value());
+
+       /* @ = formatting marks.
+        * @b = bold, i.e. a directory. Erease '@b[' and ']' */
+
+       if (selected_item[0] == '@') {
+               if (selected_item[1] == 'b') {
+                       selected_item.erase(0, 3);
+                       selected_item.erase(selected_item.size()-1, 1);
+               }
+               else
+               if (selected_item[1] == 'i')
+                       selected_item.erase(0, 4);
+       }
+
+#if defined(__linux__) || defined(__APPLE__)
+
+       /* add path to file name, to get an absolute path. Avoid double
+        * slashes like '//' */
+
+       if (strcmp("/", path_obj->value()))
+               selected_item.insert(0, "/");
+
+       selected_item.insert(0, path_obj->value());
+       return selected_item.c_str();
+#elif defined(_WIN32)
+
+       /* if path is 'All drives' we are in the devices list and the user
+        * has clicked on a device such as 'X:\' */
+
+       if (strcmp(path_obj->value(), "All drives") == 0)
+                       return selected_item.c_str();
+       else {
+
+               /* add '\' if the path is like 'X:\' */
+
+               if (strlen(path_obj->value()) > 3) /// shouln't it be == 3?
+                       selected_item.insert(0, "\\");
+
+               selected_item.insert(0, path_obj->value());
+               return selected_item.c_str();
+       }
+#endif
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+#ifdef _WIN32
+void gBrowser::showDrives() {
+
+       /* GetLogicalDriveStrings fills drives like that:
+        *
+        * a:\[null]b:\[null]c:\[null]...[null][null]
+        *
+        * where [null] stands for \0. */
+
+       char drives[64];
+       char *i = drives;               // pointer to 0th element in drives
+       GetLogicalDriveStrings(64, drives);
+
+       /* code stolen from the web, still unknown. (Jan 09, 2012). */
+
+       while (*i) {
+               add(i);
+               i = &i[strlen(i) + 1];
+       }
+}
+
+#endif
diff --git a/src/gui/elems/ge_browser.h b/src/gui/elems/ge_browser.h
new file mode 100644 (file)
index 0000000..8445319
--- /dev/null
@@ -0,0 +1,68 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_browser
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GE_BROWSER_H
+#define GE_BROWSER_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <string>
+#include "ge_mixed.h"
+
+class gBrowser : public Fl_Hold_Browser {
+public:
+       gBrowser(int x, int y, int w, int h, const char *L=0);
+       ~gBrowser();
+       void init(const char *init_path=NULL);
+       void refresh();
+       void sort();
+       void up_dir();
+       void down_dir(const char *path);
+       const char *get_selected_item();
+
+       /* path_obj
+        * the actual path*/
+
+       class gInput *path_obj;
+
+       /* selected_item
+        * choosen item */
+
+       std::string selected_item;
+
+#ifdef _WIN32
+private:
+
+       /* showDrives [WIN32 only]
+        * lists all the available drivers */
+
+       void showDrives();
+#endif
+};
+
+#endif
diff --git a/src/gui/elems/ge_channel.cpp b/src/gui/elems/ge_channel.cpp
new file mode 100644 (file)
index 0000000..945ece4
--- /dev/null
@@ -0,0 +1,148 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/pluginHost.h"
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch.h"
+#include "../../core/graphics.h"
+#include "../../core/channel.h"
+#include "../../core/wave.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/gui_utils.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiInput.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_warnings.h"
+#include "../dialogs/gd_browser.h"
+#include "../dialogs/gd_midiOutput.h"
+#include "ge_keyboard.h"
+#include "ge_channel.h"
+#include "ge_sampleChannel.h"
+
+#ifdef WITH_VST
+#include "../dialogs/gd_pluginList.h"
+#endif
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch                G_Patch;
+extern gdMainWindow *mainWin;
+
+
+gChannel::gChannel(int X, int Y, int W, int H, int type)
+ : Fl_Group(X, Y, W, H, NULL), type(type) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gChannel::getColumnIndex()
+{
+       return ((gColumn*)parent())->getIndex();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannel::blink()
+{
+       if (gu_getBlinker() > 6)
+               mainButton->setPlayMode();
+       else
+    mainButton->setDefaultMode();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannel::setColorsByStatus(int playStatus, int recStatus)
+{
+  switch (playStatus) {
+    case STATUS_OFF:
+               mainButton->setDefaultMode();
+      button->imgOn  = channelPlay_xpm;
+      button->imgOff = channelStop_xpm;
+      button->redraw();
+      break;
+    case STATUS_PLAY:
+      mainButton->setPlayMode();
+      button->imgOn  = channelStop_xpm;
+      button->imgOff = channelPlay_xpm;
+      button->redraw();
+      break;
+    case STATUS_WAIT:
+      blink();
+      break;
+    case STATUS_ENDING:
+      mainButton->setEndingMode();
+      break;
+  }
+
+  switch (recStatus) {
+    case REC_WAITING:
+      blink();
+      break;
+    case REC_ENDING:
+      mainButton->setEndingMode();
+      break;
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gChannel::handleKey(int e, int key)
+{
+       int ret;
+       if (e == FL_KEYDOWN && button->value())                              // key already pressed! skip it
+               ret = 1;
+       else
+       if (Fl::event_key() == key && !button->value()) {
+               button->take_focus();                                              // move focus to this button
+               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
+               button->do_callback();                                             // invoke the button's callback
+               ret = 1;
+       }
+       else
+               ret = 0;
+
+       if (Fl::event_key() == key)
+               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
+
+       return ret;
+}
diff --git a/src/gui/elems/ge_channel.h b/src/gui/elems/ge_channel.h
new file mode 100644 (file)
index 0000000..5af2d64
--- /dev/null
@@ -0,0 +1,119 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_CHANNEL_H
+#define GE_CHANNEL_H
+
+
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Menu_Button.H>
+#include "ge_mixed.h"
+
+
+class gChannel : public Fl_Group
+{
+protected:
+
+       /* define some breakpoints for dynamic resize */
+
+#ifdef WITH_VST
+       static const int BREAK_READ_ACTIONS = 212;
+       static const int BREAK_MODE_BOX     = 188;
+       static const int BREAK_FX           = 164;
+       static const int BREAK_DELTA        = 120;
+#else
+       static const int BREAK_READ_ACTIONS = 188;
+       static const int BREAK_MODE_BOX     = 164;
+       static const int BREAK_FX           = 140;
+       static const int BREAK_DELTA        = 96;
+#endif
+       static const int BREAK_UNIT         = 24;
+
+       /* blink
+        * blink button when channel is in wait/ending status. */
+
+       void blink();
+
+       /* setColorByStatus
+        * update colors depending on channel status. */
+
+       void setColorsByStatus(int playStatus, int recStatus);
+
+       /* handleKey
+        * method wrapped by virtual handle(int e). */
+
+       int handleKey(int e, int key);
+
+public:
+
+       gChannel(int x, int y, int w, int h, int type);
+
+       /* reset
+        * reset channel to initial status. */
+
+       virtual void reset() = 0;
+
+       /* update
+        * update the label of sample button and everything else such as 'R'
+        * button, key box and so on, according to global values. */
+
+       virtual void update() = 0;
+
+       /* refresh
+        * update graphics. */
+
+       virtual void refresh() = 0;
+
+       /* keypress
+        * what to do when the corresponding key is pressed. */
+
+       virtual int keyPress(int event) = 0;
+
+       /* getColumnIndex
+        * return the numeric index of the column in which this channel is
+        * located. */
+
+       int getColumnIndex();
+
+       class gButton        *button;
+       class gStatus        *status;
+       class gChannelButton *mainButton;
+       class gDial          *vol;
+       class gClick           *mute;
+       class gClick           *solo;
+#ifdef WITH_VST
+       class gFxButton      *fx;
+#endif
+
+       int type;
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_channelButton.cpp b/src/gui/elems/ge_channelButton.cpp
new file mode 100644 (file)
index 0000000..4eef502
--- /dev/null
@@ -0,0 +1,118 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channelButton
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/const.h"
+#include "ge_channelButton.h"
+
+
+gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l)
+  : gClick(x, y, w, h, l), key("") {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setKey(const char *k)
+{
+  key = k;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::draw()
+{
+  gClick::draw();
+
+  if (key == "")
+    return;
+
+  /* draw background */
+
+  fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
+
+  /* draw key */
+
+  fl_color(COLOR_TEXT_0);
+  fl_font(FL_HELVETICA, 11);
+  fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setInputRecordMode()
+{
+  bgColor0 = COLOR_BG_3;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setActionRecordMode()
+{
+  bgColor0 = COLOR_BG_4;
+  txtColor = COLOR_TEXT_0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setDefaultMode(const char *l)
+{
+  bgColor0 = COLOR_BG_0;
+       bdColor  = COLOR_BD_0;
+       txtColor = COLOR_TEXT_0;
+  if (l)
+    label(l);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setPlayMode()
+{
+  bgColor0 = COLOR_BG_2;
+  bdColor  = COLOR_BD_1;
+  txtColor = COLOR_TEXT_1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gChannelButton::setEndingMode()
+{
+  bgColor0 = COLOR_BD_0;
+}
diff --git a/src/gui/elems/ge_channelButton.h b/src/gui/elems/ge_channelButton.h
new file mode 100644 (file)
index 0000000..a3bb22b
--- /dev/null
@@ -0,0 +1,59 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channelButton
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_CHANNEL_BUTTON_H
+#define GE_CHANNEL_BUTTON_H
+
+
+#include "ge_mixed.h"
+
+
+class gChannelButton : public gClick
+{
+private:
+
+       std::string key;
+
+public:
+
+       gChannelButton(int x, int y, int w, int h, const char *l=0);
+
+       virtual int handle(int e) = 0;
+
+       void draw();
+       void setKey(const char *k);
+       void setPlayMode();
+       void setEndingMode();
+       void setDefaultMode(const char *l=0);
+       void setInputRecordMode();
+       void setActionRecordMode();
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_column.cpp b/src/gui/elems/ge_column.cpp
new file mode 100644 (file)
index 0000000..12c479c
--- /dev/null
@@ -0,0 +1,304 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_column
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_warnings.h"
+#include "../elems/ge_keyboard.h"
+#include "ge_column.h"
+#include "ge_channel.h"
+#include "ge_sampleChannel.h"
+#include "ge_midiChannel.h"
+
+#ifdef WITH_VST
+       #include "../dialogs/gd_pluginList.h"
+#endif
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch                G_Patch;
+extern gdMainWindow *mainWin;
+
+
+gColumn::gColumn(int X, int Y, int W, int H, int index, gKeyboard *parent)
+       : Fl_Group(X, Y, W, H), parent(parent), index(index)
+{
+  /* gColumn does a bit of a mess: we pass a pointer to its parent (gKeyboard) and
+  the gColumn itself deals with the creation of another widget, outside gColumn
+  and inside gKeyboard, which handles the vertical resize bar (gResizerBar).
+  The resizer cannot stay inside gColumn: it needs a broader view on the other
+  side widgets. The view can be obtained from gKeyboard only (the upper level).
+  Unfortunately, parent() can be NULL: at this point (i.e the constructor)
+  gColumn is still detached from any parent. We use a custom gKeyboard *parent
+  instead. */
+
+       begin();
+       addChannelBtn = new gClick(x(), y(), w(), 20, "Add new channel");
+       end();
+
+  resizer = new gResizerBar(x()+w(), y(), 16, h(), false);
+  resizer->setMinSize(140);
+  parent->add(resizer);
+
+       addChannelBtn->callback(cb_addChannel, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gColumn::~gColumn()
+{
+  /* FIXME - this could actually cause a memory leak. resizer is
+  just removed, not deleted. But we cannot delete it right now. */
+
+  parent->remove(resizer);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gColumn::handle(int e)
+{
+       switch (e) {
+               case FL_DND_ENTER:              // return(1) for these events to 'accept' dnd
+               case FL_DND_DRAG:
+               case FL_DND_RELEASE: {
+                       return 1;
+               }
+               case FL_PASTE: {              // handle actual drop (paste) operation
+                       gVector<std::string> paths;
+                       gSplit(Fl::event_text(), "\n", &paths);
+                       bool fails = false;
+                       int result = 0;
+                       for (unsigned i=0; i<paths.size; i++) {
+                               gLog("[gColumn::handle] loading %s...\n", paths.at(i).c_str());
+                               SampleChannel *c = (SampleChannel*) glue_addChannel(index, CHANNEL_SAMPLE);
+                               result = glue_loadChannel(c, gStripFileUrl(paths.at(i).c_str()).c_str());
+                               if (result != SAMPLE_LOADED_OK) {
+                                       deleteChannel(c->guiChannel);
+                                       fails = true;
+                               }
+                       }
+                       if (fails) {
+                               if (paths.size > 1)
+                                       gdAlert("Some files were not loaded successfully.");
+                               else
+                                       parent->printChannelMessage(result);
+                       }
+                       return 1;
+               }
+       }
+
+       /* we return fl_Group::handle only if none of the cases above are fired. That
+       is because we don't want to propagate a dnd drop to all the sub widgets. */
+
+       return Fl_Group::handle(e);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::resize(int X, int Y, int W, int H)
+{
+  /* resize all children */
+
+  int ch = children();
+  for (int i=0; i<ch; i++) {
+    Fl_Widget *c = child(i);
+    c->resize(X, Y + (i * (c->h() + 4)), W, c->h());
+  }
+
+  /* resize group itself */
+
+  x(X); y(Y); w(W); h(H);
+
+  /* resize resizerBar */
+
+  resizer->size(16, H);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::refreshChannels()
+{
+       for (int i=1; i<children(); i++)
+               ((gChannel*) child(i))->refresh();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::draw()
+{
+       fl_color(fl_rgb_color(27, 27, 27));
+       fl_rectf(x(), y(), w(), h());
+
+  /* call draw and then redraw in order to avoid channel corruption when
+  scrolling horizontally */
+
+  for (int i=0; i<children(); i++) {
+    child(i)->draw();
+    child(i)->redraw();
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChannel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gChannel *gColumn::addChannel(class Channel *ch)
+{
+       gChannel *gch = NULL;
+
+       if (ch->type == CHANNEL_SAMPLE)
+               gch = (gSampleChannel*) new gSampleChannel(
+                               x(),
+                               y() + children() * 24,
+                               600, // (1) see notes below
+                               20,
+                               (SampleChannel*) ch);
+       else
+               gch = (gMidiChannel*) new gMidiChannel(
+                               x(),
+                               y() + children() * 24,
+                               w(),
+                               20,
+                               (MidiChannel*) ch);
+
+       /* (1) we create a new sample channel with a fake width, instead of w() (i.e.
+       the column width), in case the column is too narrow to display all widgets.
+       This workaround prevents the widgets to disappear if they have an initial
+       negative width. MidiChannel does not need such hack because it already fits
+       nicely in a collapsed column. */
+
+       add(gch);
+  resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop
+  gch->redraw();    // avoid corruption
+       parent->redraw(); // redraw Keyboard
+       return gch;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::deleteChannel(gChannel *gch)
+{
+       gch->hide();
+       remove(gch);
+       delete gch;
+
+       /* reposition all other channels and resize this group */
+       /** TODO
+        * reposition is useless when called by gColumn::clear(). Add a new
+        * parameter to skip the operation */
+
+       for (int i=0; i<children(); i++) {
+               gch = (gChannel*) child(i);
+               gch->position(gch->x(), y()+(i*24));
+       }
+       size(w(), children() * 24 + 66);  // evil space for drag n drop
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::__cb_addChannel()
+{
+       gLog("[gColumn::__cb_addChannel] index = %d\n", index);
+       int type = openTypeMenu();
+       if (type)
+               glue_addChannel(index, type);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gColumn::openTypeMenu()
+{
+       Fl_Menu_Item rclick_menu[] = {
+               {"Sample channel"},
+               {"MIDI channel"},
+               {0}
+       };
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(11);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (!m) return 0;
+
+       if (strcmp(m->label(), "Sample channel") == 0)
+               return CHANNEL_SAMPLE;
+       if (strcmp(m->label(), "MIDI channel") == 0)
+               return CHANNEL_MIDI;
+       return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gColumn::clear(bool full)
+{
+       if (full)
+               Fl_Group::clear();
+       else {
+               while (children() >= 2) {  // skip "add new channel" btn
+                       int i = children()-1;
+                       deleteChannel((gChannel*)child(i));
+               }
+       }
+}
diff --git a/src/gui/elems/ge_column.h b/src/gui/elems/ge_column.h
new file mode 100644 (file)
index 0000000..84ebc8a
--- /dev/null
@@ -0,0 +1,98 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_column
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_COLUMN_H
+#define GE_COLUMN_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+
+
+class gColumn : public Fl_Group
+{
+private:
+
+       static void cb_addChannel  (Fl_Widget *v, void *p);
+       inline void __cb_addChannel();
+
+       int openTypeMenu();
+
+       class gClick      *addChannelBtn;
+       class gResizerBar *resizer;
+       class gKeyboard   *parent;
+
+       int index;
+
+public:
+
+       gColumn(int x, int y, int w, int h, int index, class gKeyboard *parent);
+       ~gColumn();
+
+       /* addChannel
+        * add a new channel in this column and set the internal pointer
+        * to channel to 'ch'. */
+
+       class gChannel *addChannel(class Channel *ch);
+
+       /* handle */
+
+       int handle(int e);
+
+  /* resize
+   * custom resize behavior. */
+
+  void resize(int x, int y, int w, int h);
+
+       /* deleteChannel
+        * remove the channel 'gch' from this column. */
+
+       void deleteChannel(gChannel *gch);
+
+       /* refreshChannels
+        * update channels' graphical statues. Called on each GUI cycle. */
+
+       void refreshChannels();
+
+       /* clear
+        * remove all channels from the column. If full==true, delete also the
+        * "add new channel" button. This method ovverrides the inherited one
+        * from Fl_Group. */
+
+       void clear(bool full=false);
+
+       void draw();
+
+       inline int  getIndex()      { return index; }
+       inline void setIndex(int i) { index = i; }
+       inline bool isEmpty()       { return children() == 1; }
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_controller.cpp b/src/gui/elems/ge_controller.cpp
new file mode 100644 (file)
index 0000000..2557ae6
--- /dev/null
@@ -0,0 +1,158 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ * ge_controller
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/graphics.h"
+#include "../../glue/glue.h"
+#include "ge_mixed.h"
+#include "ge_controller.h"
+
+
+gController::gController(int x, int y)
+       : Fl_Group(x, y, 131, 25)
+{
+       begin();
+
+       rewind    = new gClick(x,  y, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
+       play      = new gClick(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm);
+       recAction = new gClick(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm);
+       recInput  = new gClick(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm);
+       metronome = new gClick(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm);
+
+       end();
+
+       resizable(NULL);   // don't resize any widget
+
+       rewind->callback(cb_rewind, (void*)this);
+
+       play->callback(cb_play);
+       play->type(FL_TOGGLE_BUTTON);
+
+       recAction->callback(cb_recAction, (void*)this);
+       recAction->type(FL_TOGGLE_BUTTON);
+
+       recInput->callback(cb_recInput, (void*)this);
+       recInput->type(FL_TOGGLE_BUTTON);
+
+       metronome->callback(cb_metronome);
+       metronome->type(FL_TOGGLE_BUTTON);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::cb_rewind   (Fl_Widget *v, void *p) { ((gController*)p)->__cb_rewind(); }
+void gController::cb_play     (Fl_Widget *v, void *p) { ((gController*)p)->__cb_play(); }
+void gController::cb_recAction(Fl_Widget *v, void *p) { ((gController*)p)->__cb_recAction(); }
+void gController::cb_recInput (Fl_Widget *v, void *p) { ((gController*)p)->__cb_recInput(); }
+void gController::cb_metronome(Fl_Widget *v, void *p) { ((gController*)p)->__cb_metronome(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::__cb_rewind()
+{
+       glue_rewindSeq();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::__cb_play()
+{
+       glue_startStopSeq();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::__cb_recAction()
+{
+       glue_startStopActionRec();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::__cb_recInput()
+{
+       glue_startStopInputRec();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::__cb_metronome()
+{
+       glue_startStopMetronome();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::updatePlay(int v)
+{
+       play->value(v);
+       play->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::updateMetronome(int v)
+{
+       metronome->value(v);
+       metronome->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::updateRecInput(int v)
+{
+       recInput->value(v);
+       recInput->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gController::updateRecAction(int v)
+{
+       recAction->value(v);
+       recAction->redraw();
+}
diff --git a/src/gui/elems/ge_controller.h b/src/gui/elems/ge_controller.h
new file mode 100644 (file)
index 0000000..7056948
--- /dev/null
@@ -0,0 +1,68 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ * ge_controller
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_CONTROLLER_H
+#define GE_CONTROLLER_H
+
+
+#include <FL/Fl_Group.H>
+
+
+class gController : public Fl_Group
+{
+private:
+
+       class gClick *rewind;
+       class gClick *play;
+       class gClick *recAction;
+       class gClick *recInput;
+       class gClick *metronome;
+
+       static void cb_rewind   (Fl_Widget *v, void *p);
+       static void cb_play     (Fl_Widget *v, void *p);
+       static void cb_recAction(Fl_Widget *v, void *p);
+       static void cb_recInput (Fl_Widget *v, void *p);
+       static void cb_metronome(Fl_Widget *v, void *p);
+
+       inline void __cb_rewind   ();
+       inline void __cb_play     ();
+       inline void __cb_recAction();
+       inline void __cb_recInput ();
+       inline void __cb_metronome();
+
+public:
+
+       gController(int x, int y);
+
+       void updatePlay     (int v);
+       void updateMetronome(int v);
+       void updateRecInput (int v);
+       void updateRecAction(int v);
+};
+
+#endif
diff --git a/src/gui/elems/ge_envelopeChannel.cpp b/src/gui/elems/ge_envelopeChannel.cpp
new file mode 100644 (file)
index 0000000..d340375
--- /dev/null
@@ -0,0 +1,399 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_envelopeWidget
+ *
+ * Parent class of any envelope controller, from volume to VST parameter
+ * automations.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/channel.h"
+#include "../../core/recorder.h"
+#include "../../core/mixer.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_keyboard.h"
+#include "ge_envelopeChannel.h"
+
+
+extern Mixer         G_Mixer;
+extern gdMainWindow *mainWin;
+
+
+gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l)
+       :       gActionWidget(x, y, 200, 80, pParent), l(l), type(type), range(range),
+               selectedPoint(-1), draggedPoint(-1)
+{
+       size(pParent->totalWidth, h());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gEnvelopeChannel::~gEnvelopeChannel() {
+       clearPoints();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int py) {
+       point p;
+       p.frame  = frame;
+       p.iValue = iValue;
+       p.fValue = fValue;
+       p.x = px;
+       p.y = py;
+       points.add(p);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gEnvelopeChannel::updateActions() {
+       for (unsigned i=0; i<points.size; i++)
+               points.at(i).x = points.at(i).frame / pParent->zoom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gEnvelopeChannel::draw() {
+
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT));
+
+       int pxOld = x()-3;
+       int pyOld = y()+1;
+       int pxNew = 0;
+       int pyNew = 0;
+
+       fl_color(COLOR_BG_2);
+
+       for (unsigned i=0; i<points.size; i++) {
+
+               pxNew = points.at(i).x+x()-3;
+               pyNew = points.at(i).y+y();
+
+               if (selectedPoint == (int) i) {
+                       fl_color(COLOR_BD_1);
+                       fl_rectf(pxNew, pyNew, 7, 7);
+                       fl_color(COLOR_BG_2);
+               }
+               else
+                       fl_rectf(pxNew, pyNew, 7, 7);
+
+               if (i > 0)
+                       fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3);
+
+               pxOld = pxNew;
+               pyOld = pyNew;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gEnvelopeChannel::handle(int e) {
+
+       /* Adding an action: no further checks required, just record it on frame
+        * mx*pParent->zoom. Deleting action is trickier: find the active
+        * point and derive from it the corresponding frame. */
+
+       int ret = 0;
+       int mx  = Fl::event_x()-x();  // mouse x
+       int my  = Fl::event_y()-y();  // mouse y
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       ret = 1;
+                       break;
+               }
+
+               case FL_MOVE: {
+                       selectedPoint = getSelectedPoint();
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH: {
+
+                       /* left click on point: drag
+                        * right click on point: delete
+                        * left click on void: add */
+
+                       if (Fl::event_button1()) {
+
+                               if (selectedPoint != -1) {
+                                       draggedPoint = selectedPoint;
+                               }
+                               else {
+
+                                       /* top & border fix */
+
+                                       if (my > h()-8) my = h()-8;
+                                       if (mx > pParent->coverX-x()) mx = pParent->coverX-x();
+
+                                       if (range == RANGE_FLOAT) {
+
+                                               /* if this is the first point ever, add other two points at the beginning
+                                                * and the end of the range */
+
+                                               if (points.size == 0) {
+                                                       addPoint(0, 0, 1.0f, 0, 1);
+                                                       recorder::rec(pParent->chan->index, type, 0, 0, 1.0f);
+                                                       addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1);
+                                                       recorder::rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f);
+                                               }
+
+                                               /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */
+
+                                               int frame   = mx * pParent->zoom;
+                                               float value = (my - h() + 8) / (float) (1 - h() + 8);
+                                               addPoint(frame, 0, value, mx, my);
+                                               recorder::rec(pParent->chan->index, type, frame, 0, value);
+                                               recorder::sortActions();
+                                               sortPoints();
+                                       }
+                                       else {
+                                               /// TODO
+                                       }
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       redraw();
+                               }
+                       }
+                       else {
+
+                               /* right click on point 0 or point size-1 deletes the entire envelope */
+
+                               if (selectedPoint != -1) {
+                                       if (selectedPoint == 0 || (unsigned) selectedPoint == points.size-1) {
+                                               recorder::clearAction(pParent->chan->index, type);
+                                               points.clear();
+                                       }
+                                       else {
+                                               recorder::deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false);
+                                               recorder::sortActions();
+                                               points.del(selectedPoint);
+                                       }
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       redraw();
+                               }
+                       }
+
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+                       if (draggedPoint != -1) {
+
+                               if (points.at(draggedPoint).x == previousXPoint) {
+                                       //gLog("nothing to do\n");
+                               }
+                               else {
+                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
+
+                                       /* x edge correction */
+
+                                       if (newFrame < 0)
+                                               newFrame = 0;
+                                       else if (newFrame > G_Mixer.totalFrames)
+                                               newFrame = G_Mixer.totalFrames;
+
+                                       /* vertical line check */
+
+                                       int vp = verticalPoint(points.at(draggedPoint));
+                                       if (vp == 1)                     newFrame -= 256;
+                                       else if (vp == -1) newFrame += 256;
+
+                                       /*  delete previous point and record a new one */
+
+                                       recorder::deleteAction(pParent->chan->index,    points.at(draggedPoint).frame, type, false);
+
+                                       if (range == RANGE_FLOAT) {
+                                               float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8);
+                                               recorder::rec(pParent->chan->index, type, newFrame, 0, value);
+                                       }
+                                       else {
+                                               /// TODO
+                                       }
+
+                                       recorder::sortActions();
+                                       points.at(draggedPoint).frame = newFrame;
+                                       draggedPoint  = -1;
+                                       selectedPoint = -1;
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       if (draggedPoint != -1) {
+
+                               /* y constraint */
+
+                               if (my > h()-8)
+                                       points.at(draggedPoint).y = h()-8;
+                               else
+                               if (my < 1)
+                                       points.at(draggedPoint).y = 1;
+                               else
+                                       points.at(draggedPoint).y = my;
+
+                               /* x constraint
+                                * constrain the point between two ends (leftBorder-point, point-point,
+                                * point-rightBorder). First & last points cannot be shifted on x */
+
+                               if (draggedPoint == 0)
+                                       points.at(draggedPoint).x = x()-8;
+                               else
+                               if ((unsigned) draggedPoint == points.size-1)
+                                       points.at(draggedPoint).x = pParent->coverX;
+                               else {
+                                       int prevPoint = points.at(draggedPoint-1).x;
+                                       int nextPoint = points.at(draggedPoint+1).x;
+                                       if (mx <= prevPoint)
+                                               points.at(draggedPoint).x = prevPoint;
+                                       else
+                                       if (mx >= nextPoint)
+                                               points.at(draggedPoint).x = nextPoint;
+                                       //else
+                                       //      points.at(draggedPoint).x = mx;
+                                       else {
+                                               if (pParent->gridTool->isOn())
+                                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mx)-1;
+                                               else
+                                                       points.at(draggedPoint).x = mx;
+                                       }
+                               }
+                               redraw();
+                       }
+
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gEnvelopeChannel::verticalPoint(const point &p) {
+       for (unsigned i=0; i<points.size; i++) {
+               if (&p == &points.at(i)) {
+                       if (i == 0 || i == points.size-1)  // first or last point
+                               return 0;
+                       else {
+                               if (points.at(i-1).x == p.x)    // vertical with point[i-1]
+                                       return -1;
+                               else
+                               if (points.at(i+1).x == p.x)    // vertical with point[i+1]
+                                       return 1;
+                       }
+                       break;
+               }
+       }
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gEnvelopeChannel::sortPoints() {
+       for (unsigned i=0; i<points.size; i++)
+               for (unsigned j=0; j<points.size; j++)
+                       if (points.at(j).x > points.at(i).x)
+                               points.swap(j, i);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gEnvelopeChannel::getSelectedPoint() {
+
+       /* point is a 7x7 dot */
+
+       for (unsigned i=0; i<points.size; i++) {
+               if (Fl::event_x() >= points.at(i).x+x()-4  &&
+                               Fl::event_x() <= points.at(i).x+x()+4  &&
+                               Fl::event_y() >= points.at(i).y+y()    &&
+                               Fl::event_y() <= points.at(i).y+y()+7)
+               return i;
+       }
+       return -1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gEnvelopeChannel::fill() {
+       points.clear();
+       for (unsigned i=0; i<recorder::global.size; i++)
+               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
+                       recorder::action *a = recorder::global.at(i).at(j);
+                       if (a->type == type && a->chan == pParent->chan->index) {
+                               if (range == RANGE_FLOAT)
+                                       addPoint(
+                                               a->frame,                      // frame
+                                               0,                             // int value (unused)
+                                               a->fValue,                     // float value
+                                               a->frame / pParent->zoom,       // x
+                                               ((1-h()+8)*a->fValue)+h()-8);  // y = (b-a)x + a (line between two points)
+                               // else: TODO
+                       }
+               }
+
+}
diff --git a/src/gui/elems/ge_envelopeChannel.h b/src/gui/elems/ge_envelopeChannel.h
new file mode 100644 (file)
index 0000000..0bb7039
--- /dev/null
@@ -0,0 +1,115 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_envelopeWidget
+ *
+ * parent class of any envelope controller, from volume to VST parameter
+ * automations.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef __GE_ENVELOPECHANNEL_H__
+#define __GE_ENVELOPECHANNEL_H__
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "../../utils/utils.h"
+#include "ge_actionWidget.h"
+
+
+class gEnvelopeChannel : public gActionWidget {
+
+       const char *l;      // internal label
+       int         type;   // type of action
+       int         range;
+
+       /* point
+        * a single dot in the graph. x = relative frame, y = relative value */
+
+       struct point {
+               int   frame;
+               int   iValue;
+               float fValue;
+               int   x;
+               int   y;
+       };
+
+       /* points
+        * array of points, filled by fillPoints() */
+
+       gVector<point> points;
+
+       /* selectedPoint
+        * which point we are selecting? */
+
+       int selectedPoint;
+
+       /* draggedPoint
+        * which point we are dragging? */
+
+       int draggedPoint;
+
+       /* previousXPoint
+        * x coordinate of point at time t-1. Used to check effective shifts */
+
+       int previousXPoint;
+
+       void draw();
+
+       int handle(int e);
+
+       int getSelectedPoint();
+
+       void sortPoints();
+
+       /* verticalPoint
+        * check if two points form a vertical line. In that case the frame value
+        * would be the same and recorder would go crazy, so shift by a small value
+        * of frames to create a minimal fadein/fadeout level. Return 0: no
+        * vertical points; return 1: vertical with the next one, return -1: vertical
+        * with the previous one. */
+
+       int verticalPoint(const point &p);
+
+public:
+       gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l);
+       ~gEnvelopeChannel();
+
+       /* addPoint
+        * add a point made of frame+value to internal points[]. */
+
+       void addPoint(int frame, int iValue=0, float fValue=0.0f, int x=-1, int y=-1);
+
+       void updateActions();
+
+       /* fill
+        * parse recorder's stack and fill the widget with points. It's up to
+        * the caller to call this method as initialization. */
+
+       void fill();
+
+       inline void clearPoints() { points.clear(); }
+};
+
+#endif
diff --git a/src/gui/elems/ge_keyboard.cpp b/src/gui/elems/ge_keyboard.cpp
new file mode 100644 (file)
index 0000000..24d47bd
--- /dev/null
@@ -0,0 +1,366 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gg_keyboard
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../core/patch.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_browser.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_warnings.h"
+#include "ge_channel.h"
+#include "ge_sampleChannel.h"
+#include "ge_keyboard.h"
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch                G_Patch;
+extern gdMainWindow *mainWin;
+
+
+int gKeyboard::indexColumn = 0;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gKeyboard::gKeyboard(int X, int Y, int W, int H)
+: Fl_Scroll    (X, Y, W, H),
+       bckspcPressed(false),
+       endPressed   (false),
+       spacePressed (false),
+       addColumnBtn (NULL)
+{
+       color(COLOR_BG_MAIN);
+       type(Fl_Scroll::BOTH_ALWAYS);
+       scrollbar.color(COLOR_BG_0);
+       scrollbar.selection_color(COLOR_BG_1);
+       scrollbar.labelcolor(COLOR_BD_1);
+       scrollbar.slider(G_BOX);
+       hscrollbar.color(COLOR_BG_0);
+       hscrollbar.selection_color(COLOR_BG_1);
+       hscrollbar.labelcolor(COLOR_BD_1);
+       hscrollbar.slider(G_BOX);
+
+       addColumnBtn = new gClick(8, y(), 200, 20, "Add new column");
+       addColumnBtn->callback(cb_addColumn, (void*) this);
+       add(addColumnBtn);
+
+       init();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::init()
+{
+       /* add 6 empty columns as init layout */
+
+       __cb_addColumn();
+       __cb_addColumn();
+       __cb_addColumn();
+       __cb_addColumn();
+       __cb_addColumn();
+       __cb_addColumn();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::freeChannel(gChannel *gch)
+{
+       gch->reset();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::deleteChannel(gChannel *gch)
+{
+       for (unsigned i=0; i<columns.size; i++) {
+               int k = columns.at(i)->find(gch);
+               if (k != columns.at(i)->children()) {
+                       columns.at(i)->deleteChannel(gch);
+                       return;
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::updateChannel(gChannel *gch)
+{
+       gch->update();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::organizeColumns()
+{
+       /* if only one column exists don't cleanup: the initial column must
+        * stay here. */
+
+       if (columns.size == 1)
+               return;
+
+       /* otherwise delete all empty columns */
+       /** FIXME - this for loop might not work correctly! */
+
+       for (unsigned i=columns.size-1; i>=1; i--) {
+               if (columns.at(i)->isEmpty()) {
+                       //Fl::delete_widget(columns.at(i));
+                       delete columns.at(i);
+                       columns.del(i);
+               }
+       }
+
+       /* compact column, avoid empty spaces */
+
+       for (unsigned i=1; i<columns.size; i++)
+               columns.at(i)->position(columns.at(i-1)->x() + columns.at(i-1)->w() + 16, y());
+
+       addColumnBtn->position(columns.last()->x() + columns.last()->w() + 16, y());
+
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) { ((gKeyboard*)p)->__cb_addColumn(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build)
+{
+       gColumn *col = getColumn(colIndex);
+
+       /* no column with index 'colIndex' found? Just create it and set its index
+       to 'colIndex'. */
+
+       if (!col) {
+               __cb_addColumn();
+               col = columns.last();
+               col->setIndex(colIndex);
+               gLog("[gKeyboard::addChannel] created new column with index=%d\n", colIndex);
+       }
+
+       gLog("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
+       return col->addChannel(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::refreshColumns()
+{
+       for (unsigned i=0; i<columns.size; i++)
+               columns.at(i)->refreshChannels();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gColumn *gKeyboard::getColumn(int index)
+{
+       for (unsigned i=0; i<columns.size; i++)
+               if (columns.at(i)->getIndex() == index)
+                       return columns.at(i);
+       return NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gKeyboard::handle(int e)
+{
+       int ret = Fl_Group::handle(e);  // assume the buttons won't handle the Keyboard events
+       switch (e) {
+               case FL_FOCUS:
+               case FL_UNFOCUS: {
+                       ret = 1;                        // enables receiving Keyboard events
+                       break;
+               }
+               case FL_SHORTCUT:           // in case widget that isn't ours has focus
+               case FL_KEYDOWN:            // Keyboard key pushed
+               case FL_KEYUP: {            // Keyboard key released
+
+                       /* rewind session. Avoid retrigs */
+
+                       if (e == FL_KEYDOWN) {
+                               if (Fl::event_key() == FL_BackSpace && !bckspcPressed) {
+                                       bckspcPressed = true;
+                                       glue_rewindSeq();
+                                       ret = 1;
+                                       break;
+                               }
+                               else if (Fl::event_key() == FL_End && !endPressed) {
+                                       endPressed = true;
+                                       glue_startStopInputRec(false);  // update gui
+                                       ret = 1;
+                                       break;
+                               }
+                               else if (Fl::event_key() == FL_Enter && !enterPressed) {
+                                       enterPressed = true;
+                                       glue_startStopActionRec();
+                                       ret = 1;
+                                       break;
+                               }
+                               else if (Fl::event_key() == ' ' && !spacePressed) {
+                                       spacePressed = true;
+                                       G_Mixer.running ? glue_stopSeq() : glue_startSeq(); // TODO - glue_startStopSeq, no core logic here
+                                       ret = 1;
+                                       break;
+                               }
+                       }
+                       else if (e == FL_KEYUP) {
+                               if (Fl::event_key() == FL_BackSpace)
+                                       bckspcPressed = false;
+                               else if (Fl::event_key() == FL_End)
+                                       endPressed = false;
+                               else if (Fl::event_key() == ' ')
+                                       spacePressed = false;
+                               else if (Fl::event_key() == FL_Enter)
+                                       enterPressed = false;
+                       }
+
+                       /* Walk button arrays, trying to match button's label with the Keyboard event.
+                        * If found, set that button's value() based on up/down event,
+                        * and invoke that button's callback() */
+
+                       for (unsigned i=0; i<columns.size; i++)
+                               for (int k=1; k<columns.at(i)->children(); k++)
+                                       ret &= ((gChannel*)columns.at(i)->child(k))->keyPress(e);
+                       break;
+               }
+       }
+       return ret;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::clear()
+{
+       for (unsigned i=0; i<columns.size; i++)
+               delete columns.at(i);
+       columns.clear();
+       indexColumn = 0;     // new columns will start from index=0
+       addColumnBtn->position(8, y());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::setChannelWithActions(gSampleChannel *gch)
+{
+       if (gch->ch->hasActions)
+               gch->addActionButton();
+       else
+               gch->delActionButton();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::printChannelMessage(int res)
+{
+       if      (res == SAMPLE_NOT_VALID)
+               gdAlert("This is not a valid WAVE file.");
+       else if (res == SAMPLE_MULTICHANNEL)
+               gdAlert("Multichannel samples not supported.");
+       else if (res == SAMPLE_WRONG_BIT)
+               gdAlert("This sample has an\nunsupported bit-depth (> 32 bit).");
+       else if (res == SAMPLE_WRONG_ENDIAN)
+               gdAlert("This sample has a wrong\nbyte order (not little-endian).");
+       else if (res == SAMPLE_WRONG_FORMAT)
+               gdAlert("This sample is encoded in\nan unsupported audio format.");
+       else if (res == SAMPLE_READ_ERROR)
+               gdAlert("Unable to read this sample.");
+       else if (res == SAMPLE_PATH_TOO_LONG)
+               gdAlert("File path too long.");
+       else
+               gdAlert("Unknown error.");
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void gKeyboard::__cb_addColumn()
+{
+       int colx;
+       int colxw;
+       int colw = 380;
+       if (columns.size == 0) {
+               colx  = x() - xposition();  // mind the offset with xposition()
+               colxw = colx + colw;
+       }
+       else {
+               gColumn *prev = columns.last();
+               colx  = prev->x()+prev->w() + 16;
+               colxw = colx + colw;
+       }
+
+       /* add gColumn to gKeyboard and to columns vector */
+
+       gColumn *gc = new gColumn(colx, y(), colw-20, 2000, indexColumn, this);
+  add(gc);
+       columns.add(gc);
+       indexColumn++;
+
+       /* move addColumn button */
+
+       addColumnBtn->position(colxw-4, y());
+       redraw();
+
+       gLog("[gKeyboard::__cb_addColumn] new column added (index = %d), total count=%d, addColumn(x)=%d\n",
+               gc->getIndex(), columns.size, addColumnBtn->x());
+}
diff --git a/src/gui/elems/ge_keyboard.h b/src/gui/elems/ge_keyboard.h
new file mode 100644 (file)
index 0000000..be79c39
--- /dev/null
@@ -0,0 +1,145 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gg_keyboard
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_KEYBOARD_H
+#define GE_KEYBOARD_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Menu_Button.H>
+#include "../elems/ge_column.h"
+#include "../../utils/utils.h"
+
+
+class gKeyboard : public Fl_Scroll
+{
+private:
+
+       static void cb_addColumn  (Fl_Widget *v, void *p);
+       inline void __cb_addColumn();
+
+       bool bckspcPressed;
+       bool endPressed;
+       bool spacePressed;
+       bool enterPressed;
+
+       /* indexColumn
+        * the last index used for column. */
+
+       static int indexColumn;
+
+       class gClick *addColumnBtn;
+
+       /* columns
+        * a vector of columns which in turn contain channels. */
+
+       gVector<gColumn*> columns;
+
+public:
+
+       gKeyboard(int X, int Y, int W, int H);
+
+       int handle(int e);
+
+       /* init
+        * build the initial setup of empty channels. */
+
+       void init();
+
+       /* addChannel
+        * add a new channel to gChannels. Used by callbacks and during
+        * patch loading. Requires Channel (and not gChannel). If build is
+        * set to true, also generate the corresponding column.*/
+
+       gChannel *addChannel(int column, class Channel *ch, bool build=false);
+
+       /* deleteChannel
+        * delete a channel from gChannels<> where gChannel->ch == ch and remove
+        * it from the stack. */
+
+       void deleteChannel(gChannel *gch);
+
+       /* freeChannel
+        * free a channel from gChannels<> where gChannel->ch == ch. No channels
+        * are deleted */
+
+       void freeChannel(gChannel *gch);
+
+       /* updateChannel
+        * wrapper function to call gch->update(). */
+
+       void updateChannel(gChannel *gch);
+
+       /* organizeColumns
+        * reorganize columns layout by removing empty gaps. */
+
+       void organizeColumns();
+
+       /* refreshColumns
+        * refresh each column's channel, called on each GUI cycle. */
+
+       void refreshColumns();
+
+       /* getColumn
+        * return the column with index 'index', or NULL if not found. */
+
+       gColumn *getColumn(int index);
+
+       /* clear
+        * delete all channels and groups. */
+
+       void clear();
+
+       /* setChannelWithActions
+        * add 'R' button if channel has actions, and set recorder to active. */
+
+       void setChannelWithActions(class gSampleChannel *gch);
+
+       /* printChannelMessage
+        * given any output by glue_loadChannel, print the message on screen
+        * on a gdAlert subwindow. */
+
+       void printChannelMessage(int res);
+
+       /* getTotalColumns */
+
+       inline unsigned getTotalColumns() { return columns.size; }
+
+       /* getColumnWidth
+        * return the width in pixel of i-th column. Warning: 'i' is the i-th column
+        * in the column array, NOT the index. */
+
+       inline int getColumnWidth(int i) { return getColumn(i)->w(); }
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_midiChannel.cpp b/src/gui/elems/ge_midiChannel.cpp
new file mode 100644 (file)
index 0000000..68ba4e7
--- /dev/null
@@ -0,0 +1,340 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/pluginHost.h"
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch.h"
+#include "../../core/graphics.h"
+#include "../../core/channel.h"
+#include "../../core/wave.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/gui_utils.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiInput.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_warnings.h"
+#include "../dialogs/gd_browser.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiOutput.h"
+#include "ge_keyboard.h"
+#include "ge_midiChannel.h"
+#include "ge_channel.h"
+#include "ge_sampleChannel.h"
+
+#ifdef WITH_VST
+#include "../dialogs/gd_pluginList.h"
+#endif
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch                G_Patch;
+extern gdMainWindow *mainWin;
+
+
+gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch)
+       : gChannel(X, Y, W, H, CHANNEL_MIDI), ch(ch)
+{
+       begin();
+
+#if defined(WITH_VST)
+  int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
+#else
+       int delta = 96; // (4 widgets * 20) + (4 paddings * 4)
+#endif
+
+       button     = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
+       mainButton = new gMidiChannelButton(button->x()+button->w()+4, y(), w() - delta, 20, "-- MIDI --");
+       mute       = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
+       solo       = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+#if defined(WITH_VST)
+       fx         = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
+       vol        = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
+#else
+       vol        = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
+#endif
+
+       end();
+
+  resizable(mainButton);
+
+       update();
+
+       button->callback(cb_button, (void*)this);
+       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
+
+#ifdef WITH_VST
+       fx->callback(cb_openFxWindow, (void*)this);
+#endif
+
+       mute->type(FL_TOGGLE_BUTTON);
+       mute->callback(cb_mute, (void*)this);
+
+       solo->type(FL_TOGGLE_BUTTON);
+       solo->callback(cb_solo, (void*)this);
+
+       mainButton->callback(cb_openMenu, (void*)this);
+       vol->callback(cb_changeVol, (void*)this);
+
+       ch->guiChannel = this;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::cb_button      (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_button(); }
+void gMidiChannel::cb_mute        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_mute(); }
+void gMidiChannel::cb_solo        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_solo(); }
+void gMidiChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openMenu(); }
+void gMidiChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_changeVol(); }
+#ifdef WITH_VST
+void gMidiChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openFxWindow(); }
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::__cb_mute()
+{
+       glue_setMute(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::__cb_solo()
+{
+       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::__cb_changeVol()
+{
+       glue_setChanVol(ch, vol->value());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+void gMidiChannel::__cb_openFxWindow()
+{
+       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::__cb_button()
+{
+       if (button->value())
+               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::__cb_openMenu()
+{
+       Fl_Menu_Item rclick_menu[] = {
+               {"Edit actions..."},                        // 0
+               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 1
+                       {"All"},                                  // 2
+                       {0},                                      // 3
+               {"Setup keyboard input..."},                // 5
+               {"Setup MIDI input..."},                    // 6
+               {"Setup MIDI output..."},                   // 7
+               {"Delete channel"},                         // 8
+               {0}
+       };
+
+       /* no 'clear actions' if there are no actions */
+
+       if (!ch->hasActions)
+               rclick_menu[1].deactivate();
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(11);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+       if (strcmp(m->label(), "Delete channel") == 0) {
+               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+                       return;
+               glue_deleteChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
+               gu_openSubWindow(mainWin, new gdKeyGrabber(ch), 0);
+               //new gdKeyGrabber(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "All") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+                       return;
+               recorder::clearChan(ch->index);
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit actions...") == 0) {
+               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0);
+               gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0);
+               return;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::refresh()
+{
+       setColorsByStatus(ch->status, ch->recStatus);
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::reset()
+{
+       mainButton->setDefaultMode("-- MIDI --");
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::update()
+{
+       if (ch->midiOut) {
+               char tmp[32];
+               sprintf(tmp, "-- MIDI (channel %d) --", ch->midiOutChan+1);
+               mainButton->copy_label(tmp);
+       }
+       else
+               mainButton->label("-- MIDI --");
+
+       vol->value(ch->volume);
+       mute->value(ch->mute);
+       solo->value(ch->solo);
+
+#ifdef WITH_VST
+       fx->full = ch->plugins.size > 0;
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gMidiChannel::resize(int X, int Y, int W, int H)
+{
+  gChannel::resize(X, Y, W, H);
+
+       /* this stuff makes sense only with FX button available. Do nothing
+        * otherwise */
+
+#ifdef WITH_VST
+       if (w() < BREAK_FX) {
+               fx->hide();
+
+               mainButton->size(w() - (BREAK_DELTA - BREAK_UNIT), mainButton->h());
+       }
+       else {
+               fx->show();
+               mainButton->size(w() - BREAK_DELTA, mainButton->h());
+       }
+       mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
+       solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
+
+       gChannel::init_sizes();
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gMidiChannel::keyPress(int e)
+{
+       return handleKey(e, ch->key);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gMidiChannelButton::gMidiChannelButton(int x, int y, int w, int h, const char *l)
+       : gChannelButton(x, y, w, h, l) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gMidiChannelButton::handle(int e)
+{
+       // MIDI drag-n-drop does nothing so far.
+       return gClick::handle(e);
+}
diff --git a/src/gui/elems/ge_midiChannel.h b/src/gui/elems/ge_midiChannel.h
new file mode 100644 (file)
index 0000000..d08669d
--- /dev/null
@@ -0,0 +1,90 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_MIDI_CHANNEL_H
+#define GE_MIDI_CHANNEL_H
+
+
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Menu_Button.H>
+#include "ge_channel.h"
+#include "ge_channelButton.h"
+#include "ge_mixed.h"
+
+
+class gMidiChannel : public gChannel
+{
+private:
+
+       static void cb_button        (Fl_Widget *v, void *p);
+       static void cb_mute          (Fl_Widget *v, void *p);
+       static void cb_solo          (Fl_Widget *v, void *p);
+       static void cb_openMenu      (Fl_Widget *v, void *p);
+       static void cb_changeVol     (Fl_Widget *v, void *p);
+#ifdef WITH_VST
+       static void cb_openFxWindow  (Fl_Widget *v, void *p);
+#endif
+
+       inline void __cb_mute        ();
+       inline void __cb_solo        ();
+       inline void __cb_changeVol   ();
+       inline void __cb_button      ();
+       inline void __cb_openMenu    ();
+       inline void __cb_readActions ();
+#ifdef WITH_VST
+       inline void __cb_openFxWindow();
+#endif
+
+public:
+
+       gMidiChannel(int x, int y, int w, int h,  class MidiChannel *ch);
+
+       void reset   ();
+       void update  ();
+       void refresh ();
+       int  keyPress(int event);
+       void resize  (int x, int y, int w, int h);
+
+       class MidiChannel *ch;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gMidiChannelButton : public gChannelButton
+{
+public:
+       gMidiChannelButton(int x, int y, int w, int h, const char *l=0);
+       int handle(int e);
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_midiIoTools.cpp b/src/gui/elems/ge_midiIoTools.cpp
new file mode 100644 (file)
index 0000000..da9b873
--- /dev/null
@@ -0,0 +1,105 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiIoTools
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "ge_midiIoTools.h"
+#include "ge_mixed.h"
+
+
+gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param)
+       : Fl_Group(X, Y, W, 20),
+               callback(cb),
+               param   (param)
+{
+       begin();
+       text   = new gBox(x(), y(), 156, 20, l);
+       value  = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)");
+       button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn");
+       end();
+
+       text->box(G_BOX);
+       text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+
+       value->box(G_BOX);
+       value->callback(cb_value, (void*)this);
+       value->when(FL_WHEN_RELEASE);
+       updateValue();
+
+       button->type(FL_TOGGLE_BUTTON);
+       button->callback(cb_button, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::updateValue() {
+       char buf[16];
+       if (*param != 0x0)
+               snprintf(buf, 9, "0x%X", *param);
+       else
+               snprintf(buf, 16, "(not set)");
+       value->copy_label(buf);
+       button->value(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); }
+void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::__cb_value() {
+       if (Fl::event_button() == FL_RIGHT_MOUSE) {
+               *param = 0x0;
+               updateValue();
+       }
+       /// TODO - elif (LEFT_MOUSE) : insert values by hand
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* FIXME - do not malloc on each callback! do it on the constructor! */
+
+void gLearner::__cb_button() {
+       if (button->value() == 1) {
+               cbData *data  = (cbData*) malloc(sizeof(cbData));
+               data->window  = (gdMidiInput*) parent();  // parent = gdMidiGrabberChannel
+               data->learner = this;
+               kernelMidi::startMidiLearn(callback, (void*)data);
+       }
+       else
+               kernelMidi::stopMidiLearn();
+}
diff --git a/src/gui/elems/ge_midiIoTools.h b/src/gui/elems/ge_midiIoTools.h
new file mode 100644 (file)
index 0000000..abec2df
--- /dev/null
@@ -0,0 +1,92 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiIoTools
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_LEARNER_H
+#define GE_LEARNER_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "../../core/kernelMidi.h"
+#include "../dialogs/gd_midiInput.h"
+
+
+class gLearner : public Fl_Group
+{
+private:
+
+       /* callback
+        * cb to pass to kernelMidi. Requires two parameters:
+        * uint32_t msg - MIDI message
+        * void   *data - extra data */
+
+       kernelMidi::cb_midiLearn *callback;
+
+       class gBox    *text;
+       class gClick  *value;
+       class gButton *button;
+
+       static void cb_button(Fl_Widget *v, void *p);
+       static void cb_value (Fl_Widget *v, void *p);
+       inline void __cb_button();
+       inline void __cb_value();
+
+public:
+
+       /* param
+        * pointer to ch->midiIn[value] */
+
+       uint32_t *param;
+
+       gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param);
+
+       void updateValue();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* cbData
+ * struct we pass to kernelMidi as extra parameter. Local scope made
+ * with unnamed namespace. Infos:
+ * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */
+
+/* TODO - instead of the unnamed namespace, why don't we make the struct as a
+(static) member of gLearner? */
+
+namespace {
+       struct cbData {
+               gdMidiInput *window;
+               gLearner    *learner;
+       };
+}
+
+
+#endif
diff --git a/src/gui/elems/ge_mixed.cpp b/src/gui/elems/ge_mixed.cpp
new file mode 100644 (file)
index 0000000..ef166a6
--- /dev/null
@@ -0,0 +1,666 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_mixed
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <math.h>
+#include "../../core/const.h"
+#include "../../core/mixer.h"
+#include "../../core/graphics.h"
+#include "../../core/recorder.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../utils/gui_utils.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_mixed.h"
+
+
+extern Mixer         G_Mixer;
+extern unsigned      G_beats;
+extern bool          G_audio_status;
+extern gdMainWindow *mainWin;
+
+
+void __cb_window_closer(Fl_Widget *v, void *p)
+{
+  delete (Fl_Window*)p;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gButton::gButton(int X, int Y, int W, int H, const char *L, const char **imgOff, const char **imgOn)
+  : gClick(X, Y, W, H, L, imgOff, imgOn) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gClick::gClick(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn)
+: gBaseButton(x, y, w, h, L),
+  imgOff(imgOff),
+  imgOn(imgOn),
+  bgColor0(COLOR_BG_0),
+  bgColor1(COLOR_BG_1),
+  bdColor(COLOR_BD_0),
+  txtColor(COLOR_TEXT_0)  {}
+
+void gClick::draw()
+{
+  if (!active()) txtColor = bdColor;
+  else           txtColor = COLOR_TEXT_0;
+
+  fl_rect(x(), y(), w(), h(), bdColor);             // borders
+  if (value()) {                                    // -- clicked
+    if (imgOn != NULL)
+      fl_draw_pixmap(imgOn, x()+1, y()+1);
+    else
+      fl_rectf(x(), y(), w(), h(), bgColor1);       // covers the border
+  }
+  else {                                            // -- not clicked
+    fl_rectf(x()+1, y()+1, w()-2, h()-2, bgColor0); // bg inside the border
+    if (imgOff != NULL)
+      fl_draw_pixmap(imgOff, x()+1, y()+1);
+  }
+  if (!active())
+    fl_color(FL_INACTIVE_COLOR);
+
+  fl_color(txtColor);
+  fl_font(FL_HELVETICA, 11);
+  fl_draw(label(), x()+2, y(), w()-2, h(), FL_ALIGN_CENTER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gClickRepeat::gClickRepeat(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn)
+: Fl_Repeat_Button(x, y, w, h, L), imgOff(imgOff), imgOn(imgOn) {}
+
+void gClickRepeat::draw()
+{
+  if (value()) {                               // -- clicked
+    fl_rectf(x(), y(), w(), h(), COLOR_BG_1);  // bg
+    if (imgOn != NULL)
+      fl_draw_pixmap(imgOn, x()+1, y()+1);
+  }
+  else {                                       // -- not clicked
+    fl_rectf(x(), y(), w(), h(), COLOR_BG_0);  // bg
+    fl_rect(x(), y(), w(), h(), COLOR_BD_0);   // border
+    if (imgOff != NULL)
+      fl_draw_pixmap(imgOff, x()+1, y()+1);
+  }
+  if (!active())
+    fl_color(FL_INACTIVE_COLOR);
+
+  fl_color(COLOR_TEXT_0);
+  fl_font(FL_HELVETICA, 11);
+  fl_draw(label(), x(), y(), w(), h(), FL_ALIGN_CENTER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gInput::gInput(int x, int y, int w, int h, const char *L)
+: Fl_Input(x, y, w, h, L)
+{
+  //Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2);
+  box(G_BOX);
+  labelsize(11);
+  labelcolor(COLOR_TEXT_0);
+  color(COLOR_BG_DARK);
+  textcolor(COLOR_TEXT_0);
+  cursor_color(COLOR_TEXT_0);
+  selection_color(COLOR_BD_0);
+  textsize(11);
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gDial::gDial(int x, int y, int w, int h, const char *L)
+: Fl_Dial(x, y, w, h, L)
+{
+  labelsize(11);
+  labelcolor(COLOR_TEXT_0);
+  align(FL_ALIGN_LEFT);
+  type(FL_FILL_DIAL);
+  angles(0, 360);
+  color(COLOR_BG_0);            // background
+  selection_color(COLOR_BG_1);   // selection
+}
+
+void gDial::draw()
+{
+  double angle = (angle2()-angle1())*(value()-minimum())/(maximum()-minimum()) + angle1();
+
+  fl_color(COLOR_BG_0);
+  fl_pie(x(), y(), w(), h(), 270-angle1(), angle > angle1() ? 360+270-angle : 270-360-angle);
+
+  fl_color(COLOR_BD_0);
+  fl_arc(x(), y(), w(), h(), 0, 360);
+  fl_pie(x(), y(), w(), h(), 270-angle, 270-angle1());
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+gBox::gBox(int x, int y, int w, int h, const char *L, Fl_Align al)
+: Fl_Box(x, y, w, h, L)
+{
+  labelsize(11);
+  box(FL_NO_BOX);
+  labelcolor(COLOR_TEXT_0);
+  if (al != 0)
+    align(al | FL_ALIGN_INSIDE);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gCheck::gCheck(int x, int y, int w, int h, const char *L)
+: Fl_Check_Button(x, y, w, h, L) {}
+
+void gCheck::draw()
+{
+  int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0;
+
+  if (value()) {
+    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
+    fl_rectf(x(), y(), 12, 12, (Fl_Color) color);
+  }
+  else {
+    fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR);
+    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
+  }
+
+  fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
+  fl_font(FL_HELVETICA, 11);
+  fl_color(COLOR_TEXT_0);
+  fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gRadio::gRadio(int x, int y, int w, int h, const char *L)
+: Fl_Radio_Button(x, y, w, h, L) {}
+
+void gRadio::draw()
+{
+  int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0;
+
+  if (value()) {
+    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
+    fl_rectf(x(), y(), 12, 12, (Fl_Color) color);
+  }
+  else {
+    fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR);
+    fl_rect(x(), y(), 12, 12, (Fl_Color) color);
+  }
+
+  fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
+  fl_font(FL_HELVETICA, 11);
+  fl_color(COLOR_TEXT_0);
+  fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gProgress::gProgress(int x, int y, int w, int h, const char *L)
+: Fl_Progress(x, y, w, h, L) {
+  color(COLOR_BG_0, COLOR_BD_0);
+  box(G_BOX);
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gSoundMeter::gSoundMeter(int x, int y, int w, int h, const char *L)
+  : Fl_Box(x, y, w, h, L),
+    clip(false),
+    mixerPeak(0.0f),
+    peak(0.0f),
+    peak_old(0.0f),
+    db_level(0.0f),
+    db_level_old(0.0f) {}
+
+void gSoundMeter::draw()
+{
+  fl_rect(x(), y(), w(), h(), COLOR_BD_0);
+
+  /* peak = the highest value inside the frame */
+
+  peak = 0.0f;
+  float tmp_peak = 0.0f;
+
+  tmp_peak = fabs(mixerPeak);
+  if (tmp_peak > peak)
+    peak = tmp_peak;
+
+  clip = peak >= 1.0f ? true : false; // 1.0f is considered clip
+
+
+  /*  dBFS (full scale) calculation, plus decay of -2dB per frame */
+
+  db_level = 20 * log10(peak);
+  if (db_level < db_level_old)
+    if (db_level_old > -DB_MIN_SCALE)
+      db_level = db_level_old - 2.0f;
+
+  db_level_old = db_level;
+
+  /* graphical part */
+
+  float px_level = 0.0f;
+  if (db_level < 0.0f)
+    px_level = ((w()/DB_MIN_SCALE) * db_level) + w();
+  else
+    px_level = w();
+
+  fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);
+  fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !G_audio_status ? COLOR_ALERT : COLOR_BD_0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+gBeatMeter::gBeatMeter(int x, int y, int w, int h, const char *L)
+  : Fl_Box(x, y, w, h, L) {}
+
+void gBeatMeter::draw()
+{
+  int cursorW = w() / MAX_BEATS;
+  int greyX   = G_Mixer.beats * cursorW;
+
+  fl_rect(x(), y(), w(), h(), COLOR_BD_0);                                // border
+  fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR);              // bg
+  fl_rectf(x()+(G_Mixer.actualBeat*cursorW)+3, y()+3, cursorW-5, h()-6, COLOR_BG_2); // cursor
+
+  /* beat cells */
+
+  fl_color(COLOR_BD_0);
+  for (int i=1; i<=G_Mixer.beats; i++)
+    fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2);
+
+  /* bar line */
+
+  fl_color(COLOR_BG_2);
+  int delta = G_Mixer.beats / G_Mixer.bars;
+  for (int i=1; i<G_Mixer.bars; i++)
+    fl_line(x()+cursorW*(i*delta), y()+1, x()+cursorW*(i*delta), y()+h()-2);
+
+  /* unused grey area */
+
+  fl_rectf(x()+greyX+1, y()+1, w()-greyX-1,  h()-2, COLOR_BG_1);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gChoice::gChoice(int x, int y, int w, int h, const char *l, bool ang)
+  : Fl_Choice(x, y, w, h, l), angle(ang)
+{
+  labelsize(11);
+  labelcolor(COLOR_TEXT_0);
+  box(FL_BORDER_BOX);
+  textsize(11);
+  textcolor(COLOR_TEXT_0);
+  color(COLOR_BG_0);
+}
+
+
+void gChoice::draw()
+{
+  fl_rectf(x(), y(), w(), h(), COLOR_BG_0);              // bg
+  fl_rect(x(), y(), w(), h(), (Fl_Color) COLOR_BD_0);    // border
+  if (angle)
+    fl_polygon(x()+w()-8, y()+h()-1, x()+w()-1, y()+h()-8, x()+w()-1, y()+h()-1);
+
+  /* pick up the text() from the selected item (value()) and print it in
+   * the box and avoid overflows */
+
+  fl_color(!active() ? COLOR_BD_0 : COLOR_TEXT_0);
+  if (value() != -1) {
+    if (fl_width(text(value())) < w()-8) {
+      fl_draw(text(value()), x(), y(), w(), h(), FL_ALIGN_CENTER);
+    }
+    else {
+      std::string tmp = text(value());
+      int size        = tmp.size();
+      while (fl_width(tmp.c_str()) >= w()-16) {
+        tmp.resize(size);
+        size--;
+      }
+      tmp += "...";
+      fl_draw(tmp.c_str(), x(), y(), w(), h(), FL_ALIGN_CENTER);
+    }
+
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gDrawBox(int x, int y, int w, int h, Fl_Color c)
+{
+  fl_color(c);
+  fl_rectf(x, y, w, h);
+  fl_color(COLOR_BD_0);
+  fl_rect(x, y, w, h);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gLiquidScroll::gLiquidScroll(int x, int y, int w, int h, const char *l)
+  : Fl_Scroll(x, y, w, h, l)
+{
+  type(Fl_Scroll::VERTICAL);
+  scrollbar.color(COLOR_BG_0);
+  scrollbar.selection_color(COLOR_BG_1);
+  scrollbar.labelcolor(COLOR_BD_1);
+  scrollbar.slider(G_BOX);
+}
+
+
+void gLiquidScroll::resize(int X, int Y, int W, int H)
+{
+  int nc = children()-2;                // skip hscrollbar and vscrollbar
+  for ( int t=0; t<nc; t++) {           // tell children to resize to our new width
+    Fl_Widget *c = child(t);
+    c->resize(c->x(), c->y(), W-24, c->h());    // W-24: leave room for scrollbar
+  }
+  init_sizes();   // tell scroll children changed in size
+  Fl_Scroll::resize(X,Y,W,H);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gSlider::gSlider(int x, int y, int w, int h, const char *l)
+  : Fl_Slider(x, y, w, h, l)
+{
+  type(FL_HOR_FILL_SLIDER);
+
+  labelsize(11);
+  align(FL_ALIGN_LEFT);
+  labelcolor(COLOR_TEXT_0);
+
+  box(G_BOX);
+  color(COLOR_BG_0);
+  selection_color(COLOR_BD_0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gResizerBar::gResizerBar(int X,int Y,int W,int H, bool vertical)
+  : Fl_Box(X,Y,W,H), vertical(vertical)
+{
+  last_y = 0;
+  min_h  = 30;
+  if (vertical) {
+    orig_h = H;
+    labelsize(H);
+  }
+  else {
+    orig_h = W;
+    labelsize(W);
+  }
+  align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
+  labelfont(FL_COURIER);
+  visible_focus(0);
+}
+
+/*
+gResizerBar::~gResizerBar()
+{
+  gLog("------ resizerbar %p destroyed\n", (void*)this);
+}
+*/
+
+void gResizerBar::HandleDrag(int diff)
+{
+  Fl_Scroll *grp = (Fl_Scroll*)parent();
+  int top;
+  int bot;
+  if (vertical) {
+    top = y();
+    bot = y()+h();
+  }
+  else {
+    top = x();
+    bot = x()+w();
+  }
+
+  // First pass: find widget directly above us with common edge
+  //    Possibly clamp 'diff' if widget would get too small..
+
+  for (int t=0; t<grp->children(); t++) {
+    Fl_Widget *wd = grp->child(t);
+    if (vertical) {
+      if ((wd->y()+wd->h()) == top) {                           // found widget directly above?
+        if ((wd->h()+diff) < min_h)
+          diff = wd->h() - min_h;                              // clamp
+        wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);       // change height
+        break;                                                // done with first pass
+      }
+    }
+    else {
+      if ((wd->x()+wd->w()) == top) {                           // found widget directly above?
+        if ((wd->w()+diff) < min_h)
+          diff = wd->w() - min_h;                              // clamp
+        wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());       // change height
+        break;                                                // done with first pass
+      }
+    }
+  }
+
+  // Second pass: find widgets below us, move based on clamped diff
+
+  for (int t=0; t<grp->children(); t++) {
+    Fl_Widget *wd = grp->child(t);
+    if (vertical) {
+      if (wd->y() >= bot)                                     // found widget below us?
+        wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());      // change position
+    }
+    else {
+      if (wd->x() >= bot)
+        wd->resize(wd->x()+diff, wd->y(), wd->w(), wd->h());
+    }
+  }
+
+  // Change our position last
+
+  if (vertical)
+    resize(x(), y()+diff, w(), h());
+  else
+    resize(x()+diff, y(), w(), h());
+
+  grp->init_sizes();
+  grp->redraw();
+}
+
+
+int gResizerBar::handle(int e)
+{
+  int ret = 0;
+  int this_y;
+  if (vertical)
+    this_y = Fl::event_y_root();
+  else
+    this_y = Fl::event_x_root();
+  switch (e) {
+    case FL_FOCUS:
+      ret = 1;
+      break;
+    case FL_ENTER:
+      ret = 1;
+      fl_cursor(vertical ? FL_CURSOR_NS : FL_CURSOR_WE);
+      break;
+    case FL_LEAVE:
+      ret = 1;
+      fl_cursor(FL_CURSOR_DEFAULT);
+      break;
+    case FL_PUSH:
+      ret = 1;
+      last_y = this_y;
+      break;
+    case FL_DRAG:
+      HandleDrag(this_y-last_y);
+      last_y = this_y;
+      ret = 1;
+      break;
+    default: break;
+  }
+  return(Fl_Box::handle(e) | ret);
+}
+
+
+void gResizerBar::resize(int X,int Y,int W,int H)
+{
+  if (vertical)
+    Fl_Box::resize(X,Y,W,orig_h);                                // height of resizer stays constant size
+  else
+    Fl_Box::resize(X,Y,orig_h,H);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gScroll::gScroll(int x, int y, int w, int h, int t)
+  : Fl_Scroll(x, y, w, h)
+{
+  type(t);
+
+  scrollbar.color(COLOR_BG_0);
+  scrollbar.selection_color(COLOR_BG_1);
+  scrollbar.labelcolor(COLOR_BD_1);
+  scrollbar.slider(G_BOX);
+
+  hscrollbar.color(COLOR_BG_0);
+  hscrollbar.selection_color(COLOR_BG_1);
+  hscrollbar.labelcolor(COLOR_BD_1);
+  hscrollbar.slider(G_BOX);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gBaseButton::gBaseButton(int x, int y, int w, int h, const char *l)
+  : Fl_Button(x, y, w, h, l)
+{
+  initLabel = l ? l : "";
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gBaseButton::trimLabel()
+{
+  if (initLabel.empty())
+    return;
+
+  std::string out;
+  if (w() > 20) {
+    out = initLabel;
+    int len = initLabel.size();
+    while (fl_width(out.c_str(), out.size()) > w()) {
+      out = initLabel.substr(0, len) + "...";
+      len--;
+    }
+  }
+  else
+    out = "";
+    copy_label(out.c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gBaseButton::label(const char *l)
+{
+  Fl_Button::label(l);
+  initLabel = l;
+  trimLabel();
+}
+
+const char *gBaseButton::label()
+{
+  return Fl_Button::label();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gBaseButton::resize(int X, int Y, int W, int H)
+{
+  trimLabel();
+  Fl_Button::resize(X, Y, W, H);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gFxButton::gFxButton(int x, int y, int w, int h, const char **imgOff, const char **imgOn)
+  : gClick(x, y, w, h, NULL, imgOff, imgOn), full(false) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gFxButton::draw()
+{
+  gClick::draw();
+  if (full)
+    fl_draw_pixmap(imgOn, x()+1, y()+1, COLOR_BD_0);
+}
diff --git a/src/gui/elems/ge_mixed.h b/src/gui/elems/ge_mixed.h
new file mode 100644 (file)
index 0000000..26942d5
--- /dev/null
@@ -0,0 +1,355 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_mixed
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_MIXED_H
+#define GE_MIXED_H
+
+#include <stdio.h>
+#include <dirent.h>
+#include <stdint.h>  // for intptr_t
+#include <string>
+#include <FL/Fl.H>
+#include <FL/Fl_Menu_Window.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Repeat_Button.H>
+#include <FL/Fl_Check_Button.H>
+#include <FL/Fl_Box.H>
+#include <FL/fl_draw.H>
+#include <FL/Fl_Dial.H>
+#include <FL/Fl_Pixmap.H>
+#include <FL/Fl_Menu_Button.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Radio_Button.H>
+#include <FL/Fl_Progress.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Int_Input.H>
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Scroll.H>
+
+#ifdef _WIN32
+       #include <shlobj.h>  // for SHGetFolderPath
+#endif
+
+
+/* cb_window_closer
+ * callback for when closing windows. Deletes the widget (delete). */
+
+void __cb_window_closer(Fl_Widget *v, void *p);
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gBaseButton : public Fl_Button
+{
+private:
+       std::string initLabel;
+
+       void trimLabel();
+
+public:
+  gBaseButton(int x, int y, int w, int h, const char *l=0);
+  void resize(int x, int y, int w, int h);
+       void label(const char *l);
+       const char *label();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gClick
+ * a normal button. */
+
+class gClick : public gBaseButton
+{
+public:
+       gClick(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
+       void draw();
+       const char **imgOff;
+       const char **imgOn;
+       Fl_Color bgColor0;   // background not clicked
+       Fl_Color bgColor1;   // background clicked
+       Fl_Color bdColor;    // border
+       Fl_Color txtColor;       // testo
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gClickRepeat : public Fl_Repeat_Button
+{
+public:
+       gClickRepeat(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
+       void draw();
+       const char **imgOff;
+       const char **imgOn;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gButton
+ * exactly as gClick but with a unique id inside of it. Used for the buttons in
+ * channels and for FXs. */
+
+class gButton : public gClick
+{
+public:
+       gButton(int X,int Y,int W,int H,const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL);
+       int key;
+       int id;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gInput : public Fl_Input
+{
+public:
+       gInput(int x, int y, int w, int h, const char *L=0);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gDial : public Fl_Dial
+{
+public:
+       gDial(int x, int y, int w, int h, const char *L=0);
+       void draw();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gBox : public Fl_Box
+{
+public:
+       gBox(int x, int y, int w, int h, const char *L=0, Fl_Align al=FL_ALIGN_CENTER);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gCheck : public Fl_Check_Button
+{
+public:
+       gCheck(int x, int y, int w, int h, const char *L=0);
+       void draw();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gRadio : public Fl_Radio_Button
+{
+public:
+       gRadio(int x, int y, int w, int h, const char *L=0);
+       void draw();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gProgress : public Fl_Progress
+{
+public:
+       gProgress(int x, int y, int w, int h, const char *L=0);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gSoundMeter : public Fl_Box
+{
+public:
+       gSoundMeter(int X,int Y,int W,int H,const char *L=0);
+       void draw();
+       bool clip;
+       float mixerPeak;        // peak from mixer
+private:
+       float peak;
+       float peak_old;
+       float db_level;
+       float db_level_old;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gBeatMeter : public Fl_Box
+{
+public:
+       gBeatMeter(int X,int Y,int W,int H,const char *L=0);
+       void draw();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gChoice : public Fl_Choice
+{
+public:
+
+       gChoice(int X,int Y,int W,int H,const char *L=0, bool angle=true);
+       void draw();
+
+       inline void show(const char *c) {value(find_index(c)); }
+
+       bool angle;
+       int  id;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gDrawBox
+ * custom boxes in FLTK. */
+
+#define G_BOX FL_FREE_BOXTYPE
+void gDrawBox(int x, int y, int w, int h, Fl_Color c);
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gLiquidScroll
+ * custom scroll that tells children to follow scroll's width when
+ * resized. Thanks to Greg Ercolano from FLTK dev team.
+ * http://seriss.com/people/erco/fltk/ */
+
+class gLiquidScroll : public Fl_Scroll
+{
+public:
+       gLiquidScroll(int x, int y, int w, int h, const char *l=0);
+       void resize(int x, int y, int w, int h);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gScroll
+ * custom scroll with nice scrollbars and something else. */
+
+class gScroll : public Fl_Scroll
+{
+public:
+       gScroll(int x, int y, int w, int h, int type=Fl_Scroll::BOTH);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+/* gResizerBar
+ * 'resizer bar' between widgets Fl_Scroll. Thanks to Greg Ercolano from
+ * FLTK dev team. http://seriss.com/people/erco/fltk/
+ *
+ * Shows a resize cursor when hovered over.
+ * Assumes:
+ *     - Parent is an Fl_Scroll
+ *     - All children of Fl_Scroll are vertically arranged
+ *     - The widget above us has a bottom edge touching our top edge
+ *       ie. (w->y()+w->h() == this->y())
+ *
+ * When this widget is dragged:
+ *     - The widget above us (with a common edge) will be /resized/
+ *       vertically
+ *     - All children below us will be /moved/ vertically */
+
+/* TODO - use more general variable names
+ * (last_y -> last_?, min_h -> min_?, ...) */
+
+class gResizerBar : public Fl_Box
+{
+private:
+  bool vertical;
+       int  orig_h;
+       int  last_y;
+       int  min_h;   // min height for widget above us
+
+       void HandleDrag(int diff);
+
+public:
+
+  /* 'vertical' defines the bar movement. Vertical=true: the bar moves
+   * vertically (up and down). */
+
+       gResizerBar(int x, int y, int w, int h, bool vertical=true);
+       //~gResizerBar();
+
+  inline void setMinSize(int val) { min_h = val; }
+  inline int  getMinSize()        { return min_h; }
+
+  int  handle(int e);
+  void resize(int x, int y, int w, int h);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gSlider : public Fl_Slider
+{
+public:
+       gSlider(int x, int y, int w, int h, const char *l=0);
+       int id;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* gFxButton
+ * a simple gClick with 'full' parameter (i.e. has plugins). If 'full' is true,
+ * draw something somewhere. */
+
+class gFxButton : public gClick
+{
+public:
+       gFxButton(int x, int y, int w, int h, const char **imgOff=NULL, const char **imgOn=NULL);
+       void draw();
+       bool full;
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_modeBox.cpp b/src/gui/elems/ge_modeBox.cpp
new file mode 100644 (file)
index 0000000..a4c13f5
--- /dev/null
@@ -0,0 +1,109 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_modeBox
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../utils/gui_utils.h"
+#include "../../core/graphics.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/const.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_modeBox.h"
+
+
+gModeBox::gModeBox(int x, int y, int w, int h, SampleChannel *ch, const char *L)
+  : Fl_Menu_Button(x, y, w, h, L), ch(ch)
+{
+  box(G_BOX);
+  textsize(11);
+  textcolor(COLOR_TEXT_0);
+  color(COLOR_BG_0);
+
+  add("Loop . basic",      0, cb_changeMode, (void *)LOOP_BASIC);
+  add("Loop . once",       0, cb_changeMode, (void *)LOOP_ONCE);
+  add("Loop . once . bar", 0, cb_changeMode, (void *)LOOP_ONCE_BAR);
+  add("Loop . repeat",     0, cb_changeMode, (void *)LOOP_REPEAT);
+  add("Oneshot . basic",   0, cb_changeMode, (void *)SINGLE_BASIC);
+  add("Oneshot . press",   0, cb_changeMode, (void *)SINGLE_PRESS);
+  add("Oneshot . retrig",  0, cb_changeMode, (void *)SINGLE_RETRIG);
+  add("Oneshot . endless", 0, cb_changeMode, (void *)SINGLE_ENDLESS);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gModeBox::draw() {
+  fl_rect(x(), y(), w(), h(), COLOR_BD_0);    // border
+  switch (ch->mode) {
+    case LOOP_BASIC:
+      fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1);
+      break;
+    case LOOP_ONCE:
+      fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1);
+      break;
+    case LOOP_ONCE_BAR:
+      fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1);
+      break;
+    case LOOP_REPEAT:
+      fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1);
+      break;
+    case SINGLE_BASIC:
+      fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1);
+      break;
+    case SINGLE_PRESS:
+      fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1);
+      break;
+    case SINGLE_RETRIG:
+      fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1);
+      break;
+    case SINGLE_ENDLESS:
+      fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1);
+      break;
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gModeBox::cb_changeMode(Fl_Widget *v, void *p) { ((gModeBox*)v)->__cb_changeMode((intptr_t)p); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gModeBox::__cb_changeMode(int mode)
+{
+  ch->mode = mode;
+
+  /* what to do when the channel is playing and you change the mode?
+   * Nothing, since v0.5.3. Just refresh the action editor window, in
+   * case it's open */
+
+  gu_refreshActionEditor();
+}
diff --git a/src/gui/elems/ge_modeBox.h b/src/gui/elems/ge_modeBox.h
new file mode 100644 (file)
index 0000000..f6c661b
--- /dev/null
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_modeBox
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_MODEBOX_H
+#define GE_MODEBOX_H
+
+
+#include <FL/Fl_Menu_Button.H>
+
+
+class gModeBox : public Fl_Menu_Button
+{
+private:
+
+       static void cb_changeMode  (Fl_Widget *v, void *p);
+       inline void __cb_changeMode(int mode);
+
+       class SampleChannel *ch;
+
+public:
+       
+  gModeBox(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0);
+       void draw();
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_muteChannel.cpp b/src/gui/elems/ge_muteChannel.cpp
new file mode 100644 (file)
index 0000000..96f8cc8
--- /dev/null
@@ -0,0 +1,411 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_muteChannel
+ * a widget that represents mute actions inside the action editor.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../core/recorder.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../../glue/glue.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_keyboard.h"
+#include "ge_actionWidget.h"
+#include "ge_muteChannel.h"
+
+
+extern gdMainWindow *mainWin;
+extern Mixer         G_Mixer;
+
+
+gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent)
+ : gActionWidget(x, y, 200, 80, pParent), draggedPoint(-1), selectedPoint(-1)
+{
+       size(pParent->totalWidth, h());
+       extractPoints();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMuteChannel::draw() {
+
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       fl_draw("mute", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+
+       /* draw "on" and "off" labels. Must stay in background */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 9);
+       fl_draw("on",  x()+4, y(),        w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+       fl_draw("off", x()+4, y()+h()-14, w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+
+       /* draw on-off points. On = higher rect, off = lower rect. It always
+        * starts with a note_off */
+
+       fl_color(COLOR_BG_2);
+
+       int pxOld = x()+1;
+       int pxNew = 0;
+       int py    = y()+h()-5;
+       int pyDot = py-6;
+
+       for (unsigned i=0; i<points.size; i++) {
+
+               /* next px */
+
+               pxNew = points.at(i).x+x();
+
+               /* draw line from pxOld to pxNew.
+                * i % 2 == 0: first point, mute_on
+                * i % 2 != 0: second point, mute_off */
+
+               fl_line(pxOld, py, pxNew, py);
+               pxOld = pxNew;
+
+               py = i % 2 == 0 ? y()+4 : y()+h()-5;
+
+               /* draw dots (handles) */
+
+               fl_line(pxNew, y()+h()-5, pxNew, y()+4);
+
+               if (selectedPoint == (int) i) {
+                       fl_color(COLOR_BD_1);
+                       fl_rectf(pxNew-3, pyDot, 7, 7);
+                       fl_color(COLOR_BG_2);
+               }
+               else
+                       fl_rectf(pxNew-3, pyDot, 7, 7);
+       }
+
+       /* last section */
+
+       py = y()+h()-5;
+       fl_line(pxNew+3, py, pParent->coverX+x()-1, py);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMuteChannel::extractPoints() {
+
+       points.clear();
+
+       /* actions are already sorted by recorder::sortActions() */
+
+       for (unsigned i=0; i<recorder::frames.size; i++) {
+               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
+                       if (recorder::global.at(i).at(j)->chan == pParent->chan->index) {
+                               if (recorder::global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) {
+                                       point p;
+                                       p.frame = recorder::frames.at(i);
+                                       p.type  = recorder::global.at(i).at(j)->type;
+                                       p.x     = p.frame / pParent->zoom;
+                                       points.add(p);
+                                       //gLog("[gMuteChannel::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gMuteChannel::updateActions() {
+       for (unsigned i=0; i<points.size; i++)
+               points.at(i).x = points.at(i).frame / pParent->zoom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gMuteChannel::handle(int e) {
+
+       int ret = 0;
+       int mouseX = Fl::event_x()-x();
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       ret = 1;
+                       break;
+               }
+
+               case FL_MOVE: {
+                       selectedPoint = getSelectedPoint();
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH: {
+
+                       /* left click on point: drag
+                        * right click on point: delete
+                        * left click on void: add */
+
+                       if (Fl::event_button1())  {
+
+                               if (selectedPoint != -1) {
+                                       draggedPoint   = selectedPoint;
+                                       previousXPoint = points.at(selectedPoint).x;
+                               }
+                               else {
+
+                                       /* click on the grey area leads to nowhere */
+
+                                       if (mouseX > pParent->coverX) {
+                                               ret = 1;
+                                               break;
+                                       }
+
+                                       /* click in the middle of a long mute_on (between two points): new actions
+                                        * must be added in reverse: first mute_off then mute_on. Let's find the
+                                        * next point from here. */
+
+                                       unsigned nextPoint = points.size;
+                                       for (unsigned i=0; i<points.size; i++) {
+                                               if (mouseX < points.at(i).x) {
+                                                       nextPoint = i;
+                                                       break;
+                                               }
+                                       }
+
+                                       /* next point odd = mute_on [click here] mute_off
+                                        * next point even = mute_off [click here] mute_on */
+
+                                       int frame_a = mouseX * pParent->zoom;
+                                       int frame_b = frame_a+2048;
+
+                                       if (pParent->gridTool->isOn()) {
+                                               frame_a = pParent->gridTool->getSnapFrame(mouseX);
+                                               frame_b = pParent->gridTool->getSnapFrame(mouseX + pParent->gridTool->getCellSize());
+
+                                               /* with snap=on a point can fall onto another */
+
+                                               if (pointCollides(frame_a) || pointCollides(frame_b)) {
+                                                       ret = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       /* ensure frame parity */
+
+                                       if (frame_a % 2 != 0) frame_a++;
+                                       if (frame_b % 2 != 0) frame_b++;
+
+                                       /* avoid overflow: frame_b must be within the sequencer range. In that
+                                        * case shift the ON-OFF block */
+
+                                       if (frame_b >= G_Mixer.totalFrames) {
+                                               frame_b = G_Mixer.totalFrames;
+                                               frame_a = frame_b-2048;
+                                       }
+
+                                       if (nextPoint % 2 != 0) {
+                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_a);
+                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_b);
+                                       }
+                                       else {
+                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_a);
+                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_b);
+                                       }
+                                       recorder::sortActions();
+
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       extractPoints();
+                                       redraw();
+                               }
+                       }
+                       else {
+
+                               /* delete points pair */
+
+                               if (selectedPoint != -1) {
+
+                                       unsigned a;
+                                       unsigned b;
+
+                                       if (points.at(selectedPoint).type == ACTION_MUTEOFF) {
+                                               a = selectedPoint-1;
+                                               b = selectedPoint;
+                                       }
+                                       else {
+                                               a = selectedPoint;
+                                               b = selectedPoint+1;
+                                       }
+
+                                       //gLog("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n",
+                                       //              a, b, points.at(a).frame, points.at(b).frame);
+
+                                       recorder::deleteAction(pParent->chan->index, points.at(a).frame,        points.at(a).type, false); // false = don't check vals
+                                       recorder::deleteAction(pParent->chan->index,    points.at(b).frame,     points.at(b).type, false); // false = don't check vals
+                                       recorder::sortActions();
+
+                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       extractPoints();
+                                       redraw();
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+
+                       if (draggedPoint != -1) {
+
+                               if (points.at(draggedPoint).x == previousXPoint) {
+                                       //gLog("nothing to do\n");
+                               }
+                               else {
+
+                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
+
+                                       recorder::deleteAction(
+                                                       pParent->chan->index,
+                                                       points.at(draggedPoint).frame,
+                                                       points.at(draggedPoint).type,
+                                                       false);  // don't check values
+
+                                       recorder::rec(
+                                                       pParent->chan->index,
+                                                       points.at(draggedPoint).type,
+                                                       newFrame);
+
+                                       recorder::sortActions();
+
+                                       points.at(draggedPoint).frame = newFrame;
+                               }
+                       }
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       if (draggedPoint != -1) {
+
+                               /* constrain the point between two ends (leftBorder-point,
+                                * point-point, point-rightBorder) */
+
+                               int prevPoint;
+                               int nextPoint;
+
+                               if (draggedPoint == 0) {
+                                       prevPoint = 0;
+                                       nextPoint = points.at(draggedPoint+1).x - 1;
+                                       if (pParent->gridTool->isOn())
+                                               nextPoint -= pParent->gridTool->getCellSize();
+                               }
+                               else
+                               if ((unsigned) draggedPoint == points.size-1) {
+                                       prevPoint = points.at(draggedPoint-1).x + 1;
+                                       nextPoint = pParent->coverX-x();
+                                       if (pParent->gridTool->isOn())
+                                               prevPoint += pParent->gridTool->getCellSize();
+                               }
+                               else {
+                                       prevPoint = points.at(draggedPoint-1).x + 1;
+                                       nextPoint = points.at(draggedPoint+1).x - 1;
+                                       if (pParent->gridTool->isOn()) {
+                                               prevPoint += pParent->gridTool->getCellSize();
+                                               nextPoint -= pParent->gridTool->getCellSize();
+                                       }
+                               }
+
+                               if (mouseX <= prevPoint)
+                                       points.at(draggedPoint).x = prevPoint;
+                               else
+                               if (mouseX >= nextPoint)
+                                       points.at(draggedPoint).x = nextPoint;
+                               else
+                               if (pParent->gridTool->isOn())
+                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mouseX)-1;
+                               else
+                                       points.at(draggedPoint).x = mouseX;
+
+                               redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+       }
+
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gMuteChannel::pointCollides(int frame) {
+       for (unsigned i=0; i<points.size; i++)
+               if (frame == points.at(i).frame)
+                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gMuteChannel::getSelectedPoint() {
+
+       /* point is a 7x7 dot */
+
+       for (unsigned i=0; i<points.size; i++) {
+               if (Fl::event_x() >= points.at(i).x+x()-3 &&
+                               Fl::event_x() <= points.at(i).x+x()+3)
+               return i;
+       }
+       return -1;
+}
diff --git a/src/gui/elems/ge_muteChannel.h b/src/gui/elems/ge_muteChannel.h
new file mode 100644 (file)
index 0000000..e1835cb
--- /dev/null
@@ -0,0 +1,103 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_muteChannel
+ * a widget representing mute actions inside the action editor.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GE_MUTECHANNEL_H
+#define GE_MUTECHANNEL_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include <FL/fl_draw.H>
+#include "../../utils/utils.h"
+#include "ge_actionWidget.h"
+
+
+class gMuteChannel : public gActionWidget {
+
+private:
+
+       /* point
+        * a single dot in the graph. */
+
+       struct point {
+               int  frame;
+               char type;
+               int  x;
+       };
+
+       /* points
+        * array of on/off points, in frames */
+
+       gVector<point> points;
+
+       /* draggedPoint
+        * which point we are dragging? */
+
+       int draggedPoint;
+
+       /* selectedPoint
+        * which point we are selecting? */
+
+       int selectedPoint;
+
+       /* previousXPoint
+        * x coordinate of point at time t-1. Used to check effective shifts */
+
+       int previousXPoint;
+
+       /* extractPoints
+        * va a leggere l'array di azioni di Recorder ed estrae tutti i punti
+        * interessanti mute_on o mute_off. Li mette poi nel gVector points. */
+       void extractPoints();
+
+       /* getSelectedPoint
+        * ritorna l'indice di points[] in base al punto selezionato (quello
+        * con il mouse hover). Ritorna -1 se non trova niente. */
+       int getSelectedPoint();
+
+       /* pointCollides
+        * true if a point collides with another. Used while adding new points
+        * with snap active.*/
+
+       bool pointCollides(int frame);
+
+public:
+
+       gMuteChannel(int x, int y, class gdActionEditor *pParent);
+       void draw();
+       int  handle(int e);
+
+       /* updateActions
+        * calculates new points affected by the zoom. Call this one after
+        * each zoom update. */
+
+       void updateActions();
+};
+
+#endif
diff --git a/src/gui/elems/ge_pianoRoll.cpp b/src/gui/elems/ge_pianoRoll.cpp
new file mode 100644 (file)
index 0000000..c10e653
--- /dev/null
@@ -0,0 +1,730 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_pianoRoll
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/channel.h"
+#include "../../core/midiChannel.h"
+#include "../../core/const.h"
+#include "../../core/kernelMidi.h"
+#include "../../core/conf.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "ge_pianoRoll.h"
+
+
+extern gdMainWindow *mainWin;
+extern Mixer         G_Mixer;
+extern Conf             G_Conf;
+
+
+gPianoRollContainer::gPianoRollContainer(int x, int y, class gdActionEditor *pParent)
+ : Fl_Scroll(x, y, 200, 422), pParent(pParent)
+{
+       size(pParent->totalWidth, G_Conf.pianoRollH);
+       pianoRoll = new gPianoRoll(x, y, pParent->totalWidth, pParent);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gPianoRollContainer::~gPianoRollContainer() {
+       clear();
+       G_Conf.pianoRollH = h();
+       G_Conf.pianoRollY = pianoRoll->y();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRollContainer::updateActions() {
+       pianoRoll->updateActions();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRollContainer::draw() {
+
+       pianoRoll->size(this->w(), pianoRoll->h());  /// <--- not optimal
+
+       /* clear background */
+
+       fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
+
+       /* clip pianoRoll to pianoRollContainer size */
+
+       fl_push_clip(x(), y(), w(), h());
+       draw_child(*pianoRoll);
+       fl_pop_clip();
+
+       fl_color(COLOR_BD_0);
+       fl_line_style(0);
+       fl_rect(x(), y(), pParent->totalWidth, h());
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gPianoRoll::gPianoRoll(int X, int Y, int W, class gdActionEditor *pParent)
+ : gActionWidget(X, Y, W, 40, pParent)
+{
+       resizable(NULL);                      // don't resize children (i.e. pianoItem)
+       size(W, (MAX_NOTES+1) * CELL_H);      // 128 MIDI channels * 15 px height
+
+       if (G_Conf.pianoRollY == -1)
+               position(x(), y()-(h()/2));  // center
+       else
+               position(x(), G_Conf.pianoRollY);
+
+       drawSurface1();
+       drawSurface2();
+
+       /* add actions when the window is opened. Position is zoom-based. MIDI
+        * actions come always in pair: start + end. */
+
+       recorder::sortActions();
+
+       recorder::action *a2   = NULL;
+       recorder::action *prev = NULL;
+
+       for (unsigned i=0; i<recorder::frames.size; i++) {
+               for (unsigned j=0; j<recorder::global.at(i).size; j++) {
+
+                       /* don't show actions > than the grey area */
+                       /** FIXME - can we move this to the outer cycle? */
+
+                       if (recorder::frames.at(i) > G_Mixer.totalFrames)
+                               continue;
+
+                       recorder::action *a1 = recorder::global.at(i).at(j);
+
+                       if (a1->chan != pParent->chan->index)
+                               continue;
+
+                       if (a1->type == ACTION_MIDI) {
+
+                               /* if this action is == to previous one: skip it, we have already
+                                * checked it */
+
+                               if (a1 == prev) {
+                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was previous\n");
+                                       continue;
+                               }
+
+                               /* extract MIDI infos from a1: if is note off skip it, we are looking
+                                * for note on only */
+
+                               int a1_type = kernelMidi::getB1(a1->iValue);
+                               int a1_note = kernelMidi::getB2(a1->iValue);
+                               int a1_velo = kernelMidi::getB3(a1->iValue);
+
+                               if (a1_type == 0x80) {
+                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was note off\n");
+                                       continue;
+                               }
+
+                               /* search for the next action. Must have: same channel, ACTION_MIDI, greater
+                                * than a1->frame and with MIDI properties of note_off (0x80), same note
+                                * of a1, same velocity of a1 */
+
+                               recorder::getNextAction(
+                                               a1->chan,
+                                               ACTION_MIDI,
+                                               a1->frame,
+                                               &a2,
+                                               kernelMidi::getIValue(0x80, a1_note, a1_velo));
+
+                               /* next action note off found: add a new gPianoItem to piano roll */
+
+                               if (a2) {
+                                       //gLog("[gPianoRoll] ACTION_MIDI pair found, frame_a=%d frame_b=%d, note_a=%d, note_b=%d, type_a=%d, type_b=%d\n",
+                                       //      a1->frame, a2->frame, kernelMidi::getNoteValue(a1->iValue), kernelMidi::getNoteValue(a2->iValue),
+                                       //      kernelMidi::getNoteOnOff(a1->iValue), kernelMidi::getNoteOnOff(a2->iValue));
+                                       new gPianoItem(0, 0, x(), y()+3, a1, a2, pParent);
+                                       prev = a2;
+                                       a2 = NULL;
+                               }
+                               else
+                                       gLog("[gPianoRoll] recorder didn't find action!\n");
+
+                       }
+               }
+       }
+
+       end();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRoll::drawSurface1() {
+
+       surface1 = fl_create_offscreen(40, h());
+       fl_begin_offscreen(surface1);
+
+       /* warning: only w() and h() come from this widget, x and y coordinates
+        * are absolute, since we are writing in a memory chunk */
+
+       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
+
+       fl_line_style(FL_DASH, 0, NULL);
+       fl_font(FL_HELVETICA, 11);
+
+       int octave = 9;
+
+       for (int i=1; i<=MAX_NOTES+1; i++) {
+
+               /* print key note label. C C# D D# E F F# G G# A A# B */
+
+               char note[6];
+               int  step = i % 12;
+
+               switch (step) {
+                       case 1:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               sprintf(note, "%dG", octave);
+                               break;
+                       case 2:
+                               sprintf(note, "%dF#", octave);
+                               break;
+                       case 3:
+                               sprintf(note, "%dF", octave);
+                               break;
+                       case 4:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               sprintf(note, "%dE", octave);
+                               break;
+                       case 5:
+                               sprintf(note, "%dD#", octave);
+                               break;
+                       case 6:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               sprintf(note, "%dD", octave);
+                               break;
+                       case 7:
+                               sprintf(note, "%dC#", octave);
+                               break;
+                       case 8:
+                               sprintf(note, "%dC", octave);
+                               break;
+                       case 9:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               sprintf(note, "%dB", octave);
+                               break;
+                       case 10:
+                               sprintf(note, "%dA#", octave);
+                               break;
+                       case 11:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               sprintf(note, "%dA", octave);
+                               break;
+                       case 0:
+                               sprintf(note, "%dG#", octave);
+                               octave--;
+                               break;
+               }
+
+               fl_color(fl_rgb_color(54, 54, 54));
+               fl_draw(note, 4, ((i-1)*CELL_H)+1, 30, CELL_H, (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+
+               /* print horizontal line */
+
+               if (i < 128)
+                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
+       }
+
+       fl_line_style(0);
+       fl_end_offscreen();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRoll::drawSurface2() {
+       surface2 = fl_create_offscreen(40, h());
+       fl_begin_offscreen(surface2);
+       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
+       fl_color(fl_rgb_color(54, 54, 54));
+       fl_line_style(FL_DASH, 0, NULL);
+       for (int i=1; i<=MAX_NOTES+1; i++) {
+               int  step = i % 12;
+               switch (step) {
+                       case 1:
+                       case 4:
+                       case 6:
+                       case 9:
+                       case 11:
+                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
+                               break;
+               }
+               if (i < 128) {
+                       fl_color(fl_rgb_color(54, 54, 54));
+                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
+               }
+       }
+       fl_line_style(0);
+       fl_end_offscreen();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRoll::draw() {
+
+       fl_copy_offscreen(x(), y(), 40, h(), surface1, 0, 0);
+
+#if defined(__APPLE__)
+       for (int i=36; i<pParent->totalWidth; i+=36) /// TODO: i < pParent->coverX is faster
+               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 1, 0);
+#else
+       for (int i=40; i<pParent->totalWidth; i+=40) /// TODO: i < pParent->coverX is faster
+               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 0, 0);
+#endif
+
+       baseDraw(false);
+       draw_children();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gPianoRoll::handle(int e) {
+
+       int ret = Fl_Group::handle(e);
+
+       switch (e) {
+               case FL_PUSH:   {
+
+                       /* avoid click on grey area */
+
+                       if (Fl::event_x() >= pParent->coverX) {
+                               ret = 1;
+                               break;
+                       }
+
+
+                       push_y = Fl::event_y() - y();
+
+                       if (Fl::event_button1()) {
+
+                               /* ax is driven by grid, ay by the height in px of each note */
+
+                               int ax = Fl::event_x();
+                               int ay = Fl::event_y();
+
+                               /* vertical snap */
+
+                               int edge = (ay-y()-3) % 15;
+                               if (edge != 0) ay -= edge;
+
+                               /* if no overlap, add new piano item. Also check that it doesn't
+                                * overflow on the grey area, by shifting it to the left if
+                                * necessary. */
+
+                               if (!onItem(ax, ay-y()-3)) {
+                                       int greyover = ax+20 - pParent->coverX-x();
+                                       if (greyover > 0)
+                                               ax -= greyover;
+                                       add(new gPianoItem(ax, ay, ax-x(), ay-y()-3, NULL, NULL, pParent));
+                                       redraw();
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+               case FL_DRAG:   {
+
+                       if (Fl::event_button3()) {
+
+                               gPianoRollContainer *prc = (gPianoRollContainer*) parent();
+                               position(x(), Fl::event_y() - push_y);
+
+                               if (y() > prc->y())
+                                       position(x(), prc->y());
+                               else
+                               if (y() < prc->y()+prc->h()-h())
+                                       position(x(), prc->y()+prc->h()-h());
+
+                               prc->redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+               case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoRoll::updateActions() {
+
+       /* when zooming, don't delete and re-add actions, just MOVE them. This
+        * function shifts the action by a zoom factor. Those singlepress are
+        * stretched, as well */
+
+       gPianoItem *i;
+       for (int k=0; k<children(); k++) {
+               i = (gPianoItem*) child(k);
+
+               //gLog("found point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
+
+               int newX = x() + (i->getFrame_a() / pParent->zoom);
+               int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom);
+               if (newW < 8)
+                       newW = 8;
+               i->resize(newX, i->y(), newW, i->h());
+               i->redraw();
+
+               //gLog("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gPianoRoll::onItem(int rel_x, int rel_y) {
+
+       if (!pParent->chan->hasActions)
+               return false;
+
+       int note = MAX_NOTES - (rel_y / CELL_H);
+
+       int n = children();
+       for (int i=0; i<n; i++) {   // no scrollbars to skip
+
+               gPianoItem *p = (gPianoItem*) child(i);
+               if (p->getNote() != note)
+                       continue;
+
+               /* when 2 segments overlap?
+                * start = the highest value between the two starting points
+                * end   = the lowest value between the two ending points
+                * if start < end then there's an overlap of end-start pixels. We
+                * also add 1 px to the edges in order to gain some space:
+                * [   ][   ]  ---> no
+                * [   ] [   ] ---> yes! */
+
+               int start = p->x() > rel_x ? p->x() : rel_x-1;
+               int end   = p->x()+p->w() < rel_x + 20 ? p->x()+p->w() : rel_x + 21;
+               if (start < end)
+                       return true;
+       }
+       return false;
+}
+
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
+
+
+gPianoItem::gPianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, gdActionEditor *pParent)
+       : Fl_Box  (X, Y, 20, gPianoRoll::CELL_H-5),
+         a       (a),
+         b       (b),
+               pParent (pParent),
+               selected(false),
+               event_a (0x00),
+               event_b (0x00),
+               changed (false)
+{
+
+       /* a is a pointer: action exists, needs to be displayed */
+
+       if (a) {
+               note    = kernelMidi::getB2(a->iValue);
+               frame_a = a->frame;
+               frame_b = b->frame;
+               event_a = a->iValue;
+               event_b = b->iValue;
+               int newX = rel_x + (frame_a / pParent->zoom);
+               int newY = rel_y + getY(note);
+               int newW = (frame_b - frame_a) / pParent->zoom;
+               resize(newX, newY, newW, h());
+       }
+
+       /* a is null: action needs to be recorded from scratch */
+
+       else {
+               note    = getNote(rel_y);
+               frame_a = rel_x * pParent->zoom;
+               frame_b = (rel_x + 20) * pParent->zoom;
+               record();
+               size((frame_b - frame_a) / pParent->zoom, h());
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gPianoItem::overlap() {
+
+       /* when 2 segments overlap?
+        * start = the highest value between the two starting points
+        * end   = the lowest value between the two ending points
+        * if start < end then there's an overlap of end-start pixels. */
+
+       gPianoRoll *pPiano = (gPianoRoll*) parent();
+
+       for (int i=0; i<pPiano->children(); i++) {
+
+               gPianoItem *pItem = (gPianoItem*) pPiano->child(i);
+
+               /* don't check against itself and with different y positions */
+
+               if (pItem == this || pItem->y() != y())
+                       continue;
+
+               int start = pItem->x() >= x() ? pItem->x() : x();
+               int end   = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w();
+               if (start < end)
+                       return true;
+       }
+
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoItem::draw() {
+       int _w = w() > 4 ? w() : 4;
+       //gLog("[gPianoItem] draw me (%p) at x=%d\n", (void*)this, x());
+       fl_rectf(x(), y(), _w, h(), (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoItem::record() {
+
+       /* avoid frame overflow */
+
+       int overflow = frame_b - G_Mixer.totalFrames;
+       if (overflow > 0) {
+               frame_b -= overflow;
+               frame_a -= overflow;
+       }
+
+       /* note off */
+       /** FIXME - use constants */
+       event_a |= (0x90 << 24);   // note on
+       event_a |= (note << 16);   // note value
+       event_a |= (0x3F <<  8);   // velocity
+       event_a |= (0x00);
+
+       event_b |= (0x80 << 24);   // note off
+       event_b |= (note << 16);   // note value
+       event_b |= (0x3F <<  8);   // velocity
+       event_b |= (0x00);
+
+       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a);
+       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gPianoItem::remove() {
+       recorder::deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0);
+       recorder::deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0);
+
+       /* send a note-off in case we are deleting it in a middle of a key_on
+        * key_off sequence. */
+
+       ((MidiChannel*) pParent->chan)->sendMidi(event_b);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gPianoItem::handle(int e) {
+
+       int ret = 0;
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       selected = true;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       selected = false;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+
+               case FL_MOVE: {
+                       onLeftEdge  = false;
+                       onRightEdge = false;
+
+                       if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
+                               onLeftEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       }
+                       else
+                       if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
+                               onRightEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       }
+                       else
+                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH: {
+
+                       push_x = Fl::event_x() - x();
+                       old_x  = x();
+                       old_w  = w();
+
+                       if (Fl::event_button3()) {
+                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                               remove();
+                               hide();   // for Windows
+                               Fl::delete_widget(this);
+                               ((gPianoRoll*)parent())->redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       changed = true;
+
+                       gPianoRoll *pr = (gPianoRoll*) parent();
+                       int coverX     = pParent->coverX + pr->x(); // relative coverX
+                       int nx, ny, nw;
+
+                       if (onLeftEdge) {
+                               nx = Fl::event_x();
+                               ny = y();
+                               nw = x()-Fl::event_x()+w();
+                               if (nx < pr->x()) {
+                                       nx = pr->x();
+                                       nw = w()+x()-pr->x();
+                               }
+                               else
+                               if (nx > x()+w()-8) {
+                                       nx = x()+w()-8;
+                                       nw = 8;
+                               }
+                               resize(nx, ny, nw, h());
+                       }
+                       else
+                       if (onRightEdge) {
+                               nw = Fl::event_x()-x();
+                               if (Fl::event_x() < x()+8)
+                                       nw = 8;
+                               else
+                               if (Fl::event_x() > coverX)
+                                       nw = coverX-x();
+                               size(nw, h());
+                       }
+                       else {
+                               nx = Fl::event_x() - push_x;
+                               if (nx < pr->x()+1)
+                                       nx = pr->x()+1;
+                               else
+                               if (nx+w() > coverX)
+                                       nx = coverX-w();
+
+                               /* snapping */
+
+                               if (pParent->gridTool->isOn())
+                                       nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1;
+
+                               position(nx, y());
+                       }
+
+                       /* update screen */
+
+                       redraw();
+                       ((gPianoRoll*)parent())->redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+
+                       /* delete & record the action, only if it doesn't overlap with
+                        * another one */
+
+                       if (overlap()) {
+                               resize(old_x, y(), old_w, h());
+                               redraw();
+                       }
+                       else
+                       if (changed) {
+                               remove();
+                               note    = getNote(getRelY());
+                               frame_a = getRelX() * pParent->zoom;
+                               frame_b = (getRelX()+w()) * pParent->zoom;
+                               record();
+                               changed = false;
+                       }
+
+                       ((gPianoRoll*)parent())->redraw();
+
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
diff --git a/src/gui/elems/ge_pianoRoll.h b/src/gui/elems/ge_pianoRoll.h
new file mode 100644 (file)
index 0000000..aad0618
--- /dev/null
@@ -0,0 +1,183 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_pianoRoll
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GE_PIANOROLL_H
+#define GE_PIANOROLL_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Box.H>
+#include "../../core/recorder.h"
+#include "ge_actionWidget.h"
+
+
+class gPianoRollContainer : public Fl_Scroll {
+
+private:
+       class gdActionEditor *pParent;
+       class gPianoRoll     *pianoRoll;
+
+public:
+       gPianoRollContainer(int x, int y, class gdActionEditor *parent);
+       ~gPianoRollContainer();
+       void draw();
+       void updateActions();
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gPianoRoll : public gActionWidget {
+
+private:
+
+       /* onItem
+        * is curson on a gPianoItem? */
+
+       bool onItem(int rel_x, int rel_y);
+
+       /* drawSurface*
+        * generate a complex drawing in memory first and copy it to the
+        * screen at a later point in time. Fl_Offscreen surface holds the
+        * necessary data. */
+
+       /* drawSurface1
+        * draw first tile of note values. */
+
+       void drawSurface1();
+
+       /* drawSurface2
+        * draw the rest of the piano roll. */
+
+       void drawSurface2();
+
+       int  push_y;
+       Fl_Offscreen surface1;  // notes, no repeat
+       Fl_Offscreen surface2;  // lines, x-repeat
+
+
+public:
+       gPianoRoll(int x, int y, int w, class gdActionEditor *pParent);
+
+       void draw();
+       int  handle(int e);
+       void updateActions();
+
+       enum { MAX_NOTES = 127, CELL_H = 15 };
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+class gPianoItem : public Fl_Box {
+
+private:
+
+       /* getRelX/Y
+        * return x/y point of this item, relative to piano roll (and not to
+        * entire screen) */
+
+       inline int getRelY() { return y() - parent()->y() - 3; };
+       inline int getRelX() { return x() - parent()->x(); };
+
+       /* getNote
+        * from a relative_y return the real MIDI note, range 0-127. 15 is
+        * the hardcoded value for note height in pixels */
+
+       inline int getNote(int rel_y) {
+               return gPianoRoll::MAX_NOTES - (rel_y / gPianoRoll::CELL_H);
+       };
+
+       /* getY
+        * from a note, return the y position on piano roll */
+
+       inline int getY(int note) {
+               return (gPianoRoll::MAX_NOTES * gPianoRoll::CELL_H) - (note * gPianoRoll::CELL_H);
+       };
+
+       /* overlap
+        * check if this item don't overlap with another one. */
+
+       bool overlap();
+
+       recorder::action *a;
+       recorder::action *b;
+       class gdActionEditor *pParent;
+
+       bool selected;
+       int  push_x;
+
+       /* MIDI note, start frame, end frame - Used only if it's a newly added
+        * action */ /** FIXME - is it true? */
+
+       int  note;
+       int  frame_a;
+       int  frame_b;
+
+       /* event - bitmasked MIDI events, generated by record() or by ctor if
+        * not newly added action */
+
+       int event_a;
+       int event_b;
+
+       /* changed - if Item has been moved or resized: re-recording needed */
+
+       bool changed;
+
+       /* onLeft,RightEdge - if cursor is on a widget's edge */
+
+       bool onLeftEdge;
+       bool onRightEdge;
+
+       /* old_x, old_w - store previous width and position while dragging
+        * and moving, in order to restore it if overlap */
+
+       int old_x, old_w;
+
+public:
+
+       /* pianoItem ctor
+        * if action *a == NULL, record a new action */
+
+       gPianoItem(int x, int y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, class gdActionEditor *pParent);
+
+       void draw();
+       int  handle(int e);
+       void record();
+       void remove();
+
+       inline int getFrame_a() { return frame_a; }
+       inline int getFrame_b() { return frame_b; }
+       inline int getNote()    { return note;    }
+
+};
+
+#endif
diff --git a/src/gui/elems/ge_sampleChannel.cpp b/src/gui/elems/ge_sampleChannel.cpp
new file mode 100644 (file)
index 0000000..8498391
--- /dev/null
@@ -0,0 +1,600 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_sampleChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/pluginHost.h"
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch.h"
+#include "../../core/graphics.h"
+#include "../../core/channel.h"
+#include "../../core/wave.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../glue/glue.h"
+#include "../../utils/gui_utils.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiInput.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_warnings.h"
+#include "../dialogs/gd_browser.h"
+#include "../dialogs/gd_midiOutput.h"
+#include "ge_keyboard.h"
+#include "ge_sampleChannel.h"
+#include "ge_status.h"
+#include "ge_modeBox.h"
+
+#ifdef WITH_VST
+#include "../dialogs/gd_pluginList.h"
+#endif
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch                G_Patch;
+extern gdMainWindow *mainWin;
+
+
+gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel *ch)
+       : gChannel(X, Y, W, H, CHANNEL_SAMPLE), ch(ch)
+{
+       begin();
+
+#if defined(WITH_VST)
+  int delta = 168; // (7 widgets * 20) + (7 paddings * 4)
+#else
+       int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
+#endif
+
+       button       = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
+       status       = new gStatus(button->x()+button->w()+4, y(), 20, 20, ch);
+       mainButton   = new gSampleChannelButton(status->x()+status->w()+4, y(), w() - delta, 20, "-- no sample --");
+       modeBox      = new gModeBox(mainButton->x()+mainButton->w()+4, y(), 20, 20, ch);
+       mute         = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
+       solo         = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+       readActions  = NULL; // no 'R' button
+
+#if defined(WITH_VST)
+       fx           = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
+       vol          = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
+#else
+       vol          = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
+#endif
+
+       end();
+
+  resizable(mainButton);
+
+       update();
+
+       button->callback(cb_button, (void*)this);
+       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
+
+#ifdef WITH_VST
+       fx->callback(cb_openFxWindow, (void*)this);
+#endif
+
+       mute->type(FL_TOGGLE_BUTTON);
+       mute->callback(cb_mute, (void*)this);
+
+       solo->type(FL_TOGGLE_BUTTON);
+       solo->callback(cb_solo, (void*)this);
+
+       mainButton->callback(cb_openMenu, (void*)this);
+       vol->callback(cb_changeVol, (void*)this);
+
+       ch->guiChannel = this;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::cb_button      (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_button(); }
+void gSampleChannel::cb_mute        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_mute(); }
+void gSampleChannel::cb_solo        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_solo(); }
+void gSampleChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openMenu(); }
+void gSampleChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_changeVol(); }
+void gSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_readActions(); }
+#ifdef WITH_VST
+void gSampleChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openFxWindow(); }
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::__cb_mute()
+{
+       glue_setMute(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::__cb_solo()
+{
+       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::__cb_changeVol()
+{
+       glue_setChanVol(ch, vol->value());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+void gSampleChannel::__cb_openFxWindow()
+{
+       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+
+void gSampleChannel::__cb_button()
+{
+       if (button->value())    // pushed
+               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
+       else                    // released
+               glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::__cb_openMenu()
+{
+       /* if you're recording (actions or input) no menu is allowed; you can't
+        * do anything, especially deallocate the channel */
+
+       if (G_Mixer.chanInput == ch || recorder::active)
+               return;
+
+       /* the following is a trash workaround for a FLTK menu. We need a gMenu
+        * widget asap */
+
+       Fl_Menu_Item rclick_menu[] = {
+               {"Load new sample..."},                     // 0
+               {"Export sample to file..."},               // 1
+               {"Setup keyboard input..."},                // 2
+               {"Setup MIDI input..."},                    // 3
+               {"Setup MIDI output..."},                   // 4
+               {"Edit sample..."},                         // 5
+               {"Edit actions..."},                        // 6
+               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 7
+                       {"All"},                                  // 8
+                       {"Mute"},                                 // 9
+                       {"Volume"},                               // 10
+                       {"Start/Stop"},                           // 11
+                       {0},                                      // 12
+               {"Free channel"},                           // 13
+               {"Delete channel"},                         // 14
+               {0}
+       };
+
+       if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) {
+               rclick_menu[1].deactivate();
+               rclick_menu[5].deactivate();
+               rclick_menu[13].deactivate();
+       }
+
+       /* no 'clear actions' if there are no actions */
+
+       if (!ch->hasActions)
+               rclick_menu[6].deactivate();
+
+       /* no 'clear start/stop actions' for those channels in loop mode:
+        * they cannot have start/stop actions. */
+
+       if (ch->mode & LOOP_ANY)
+               rclick_menu[10].deactivate();
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(11);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+       if (strcmp(m->label(), "Load new sample...") == 0) {
+               openBrowser(BROWSER_LOAD_SAMPLE);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
+               new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit sample...") == 0) {
+               gu_openSubWindow(mainWin, new gdEditor(ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor
+               return;
+       }
+
+       if (strcmp(m->label(), "Export sample to file...") == 0) {
+               openBrowser(BROWSER_SAVE_SAMPLE);
+               return;
+       }
+
+       if (strcmp(m->label(), "Delete channel") == 0) {
+               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+                       return;
+               glue_deleteChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Free channel") == 0) {
+               if (ch->status == STATUS_PLAY) {
+                       if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
+                               return;
+               }
+               else if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
+                       return;
+
+               glue_freeChannel(ch);
+
+               /* delete any related subwindow */
+
+               /** FIXME - use gu_closeAllSubwindows() */
+
+               mainWin->delSubWindow(WID_FILE_BROWSER);
+               mainWin->delSubWindow(WID_ACTION_EDITOR);
+               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
+               mainWin->delSubWindow(WID_FX_LIST);
+
+               return;
+       }
+
+       if (strcmp(m->label(), "Mute") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
+                       return;
+               recorder::clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF);
+               if (!ch->hasActions)
+                       delActionButton();
+
+               /* TODO - set mute=false */
+
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Start/Stop") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
+                       return;
+               recorder::clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN);
+               if (!ch->hasActions)
+                       delActionButton();
+               gu_refreshActionEditor();  // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Volume") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
+                       return;
+               recorder::clearAction(ch->index, ACTION_VOLUME);
+               if (!ch->hasActions)
+                       delActionButton();
+               gu_refreshActionEditor();  // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "All") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+                       return;
+               recorder::clearChan(ch->index);
+               delActionButton();
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit actions...") == 0) {
+               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
+               return;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::__cb_readActions()
+{
+       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::openBrowser(int type)
+{
+       const char *title = "";
+       switch (type) {
+               case BROWSER_LOAD_SAMPLE:
+                       title = "Browse Sample";
+                       break;
+               case BROWSER_SAVE_SAMPLE:
+                       title = "Save Sample";
+                       break;
+               case -1:
+                       title = "Edit Sample";
+                       break;
+       }
+       gWindow *childWin = new gdBrowser(title, G_Conf.samplePath, ch, type);
+       gu_openSubWindow(mainWin, childWin,     WID_FILE_BROWSER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::refresh()
+{
+  if (!mainButton->visible()) // mainButton invisible? status too (see below)
+    return;
+
+       setColorsByStatus(ch->status, ch->recStatus);
+
+       if (ch->wave != NULL) {
+               if (G_Mixer.chanInput == ch)
+                       mainButton->setInputRecordMode();
+               if (recorder::active) {
+                       if (recorder::canRec(ch))
+                               mainButton->setActionRecordMode();
+               }
+               status->redraw(); // status invisible? sampleButton too (see below)
+       }
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::reset()
+{
+       delActionButton(true); // force==true, don't check, just remove it
+       mainButton->setDefaultMode("-- no sample --");
+       mainButton->redraw();
+       status->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::update()
+{
+       /* update sample button's label */
+
+       switch (ch->status) {
+               case STATUS_EMPTY:
+                       mainButton->label("-- no sample --");
+                       break;
+               case STATUS_MISSING:
+               case STATUS_WRONG:
+                       mainButton->label("* file not found! *");
+                       break;
+               default:
+                       mainButton->label(ch->wave->name.c_str());
+                       break;
+       }
+
+       /* update channels. If you load a patch with recorded actions, the 'R'
+        * button must be shown. Moreover if the actions are active, the 'R'
+        * button must be activated accordingly. */
+
+       if (ch->hasActions)
+               addActionButton();
+       else
+               delActionButton();
+
+       /* updates modebox */
+
+       modeBox->value(ch->mode);
+       modeBox->redraw();
+
+       /* update volumes+mute+solo */
+
+       vol->value(ch->volume);
+       mute->value(ch->mute);
+       solo->value(ch->solo);
+
+#ifdef WITH_VST
+       fx->full = ch->plugins.size > 0;
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gSampleChannel::keyPress(int e)
+{
+       return handleKey(e, ch->key);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::addActionButton()
+{
+       /* quit if 'R' exists yet. */
+
+       if (readActions != NULL)
+               return;
+
+       mainButton->size(mainButton->w()-24, mainButton->h());
+
+       redraw();
+
+       readActions = new gClick(mainButton->x() + mainButton->w() + 4,
+                           mainButton->y(), 20, 20, "", readActionOff_xpm,
+                           readActionOn_xpm);
+       readActions->type(FL_TOGGLE_BUTTON);
+       readActions->value(ch->readActions);
+       readActions->callback(cb_readActions, (void*)this);
+       add(readActions);
+
+       /* hard redraw: there's no other way to avoid glitches when moving
+        * the 'R' button */
+
+       mainWin->keyboard->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::delActionButton(bool force)
+{
+       if (readActions == NULL)
+               return;
+
+       /* TODO - readActions check is useless here */
+
+       if (!force && (readActions == NULL || ch->hasActions))
+               return;
+
+       remove(readActions);            // delete from Keyboard group (FLTK)
+       delete readActions;     // delete (C++)
+       readActions = NULL;
+
+       mainButton->size(mainButton->w()+24, mainButton->h());
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSampleChannel::resize(int X, int Y, int W, int H)
+{
+  gChannel::resize(X, Y, W, H);
+
+       if (w() < BREAK_FX) {
+#ifdef WITH_VST
+               fx->hide();
+#endif
+               mainButton->size(w() - BREAK_DELTA, mainButton->h());
+               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
+               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
+       }
+       else
+       if (w() < BREAK_MODE_BOX) {
+#ifdef WITH_VST
+               fx->show();
+#endif
+               mainButton->size(w() - (BREAK_DELTA + BREAK_UNIT), mainButton->h());
+               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
+               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
+    modeBox->hide();
+       }
+       else
+       if (w() < BREAK_READ_ACTIONS) {
+    modeBox->show();
+    mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h());
+    modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
+               if (readActions) {
+      readActions->hide();
+               }
+       }
+       else {
+               if (readActions) {
+      mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 3)), mainButton->h());
+      readActions->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
+      readActions->show();
+               }
+       }
+
+       gChannel::init_sizes();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gSampleChannelButton::gSampleChannelButton(int x, int y, int w, int h, const char *l)
+       : gChannelButton(x, y, w, h, l) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gSampleChannelButton::handle(int e)
+{
+       int ret = gClick::handle(e);
+       switch (e) {
+               case FL_DND_ENTER:
+               case FL_DND_DRAG:
+               case FL_DND_RELEASE: {
+                       ret = 1;
+                       break;
+               }
+               case FL_PASTE: {
+      gSampleChannel *gch = (gSampleChannel*) parent();   // parent is gSampleChannel
+      SampleChannel  *ch  = gch->ch;
+      int result = glue_loadChannel(ch, gTrim(gStripFileUrl(Fl::event_text())).c_str());
+                       if (result != SAMPLE_LOADED_OK)
+                               mainWin->keyboard->printChannelMessage(result);
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
diff --git a/src/gui/elems/ge_sampleChannel.h b/src/gui/elems/ge_sampleChannel.h
new file mode 100644 (file)
index 0000000..0aad470
--- /dev/null
@@ -0,0 +1,104 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_sampleChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_SAMPLE_CHANNEL_H
+#define GE_SAMPLE_CHANNEL_H
+
+
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Menu_Button.H>
+#include "ge_channel.h"
+#include "ge_channelButton.h"
+#include "ge_mixed.h"
+
+
+class gSampleChannel : public gChannel
+{
+private:
+
+       static void cb_button        (Fl_Widget *v, void *p);
+       static void cb_mute          (Fl_Widget *v, void *p);
+       static void cb_solo          (Fl_Widget *v, void *p);
+       static void cb_openMenu      (Fl_Widget *v, void *p);
+       static void cb_changeVol     (Fl_Widget *v, void *p);
+       static void cb_readActions   (Fl_Widget *v, void *p);
+#ifdef WITH_VST
+       static void cb_openFxWindow  (Fl_Widget *v, void *p);
+#endif
+
+       inline void __cb_mute        ();
+       inline void __cb_solo        ();
+       inline void __cb_changeVol   ();
+       inline void __cb_button      ();
+       inline void __cb_openMenu    ();
+       inline void __cb_readActions ();
+#ifdef WITH_VST
+       inline void __cb_openFxWindow();
+#endif
+
+       void openBrowser(int type);
+
+public:
+
+       gSampleChannel(int x, int y, int w, int h, class SampleChannel *ch);
+
+       void reset   ();
+       void update  ();
+       void refresh ();
+       int  keyPress(int event);
+       void resize  (int x, int y, int w, int h);
+
+       /* add/delActionButton
+        * add or remove 'R' button when actions are available. 'Status' is
+        * the initial status of the button: on or off.
+        * If force==true remove the button with no further checks. */
+
+       void addActionButton();
+       void delActionButton(bool force=false);
+
+       class gModeBox *modeBox;
+       class gClick     *readActions;
+
+       class SampleChannel *ch;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gSampleChannelButton : public gChannelButton
+{
+public:
+       gSampleChannelButton(int x, int y, int w, int h, const char *l=0);
+       int handle(int e);
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_status.cpp b/src/gui/elems/ge_status.cpp
new file mode 100644 (file)
index 0000000..564b9ab
--- /dev/null
@@ -0,0 +1,78 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_status
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "ge_status.h"
+
+
+extern Mixer G_Mixer;
+
+
+gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L)
+  : Fl_Box(x, y, w, h, L), ch(ch) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gStatus::draw()
+{
+  fl_rect(x(), y(), w(), h(), COLOR_BD_0);              // reset border
+  fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);     // reset background
+
+  if (ch != NULL) {
+    if (ch->status    & (STATUS_WAIT | STATUS_ENDING | REC_ENDING | REC_WAITING) ||
+        ch->recStatus & (REC_WAITING | REC_ENDING))
+    {
+      fl_rect(x(), y(), w(), h(), COLOR_BD_1);
+    }
+    else
+    if (ch->status == STATUS_PLAY)
+      fl_rect(x(), y(), w(), h(), COLOR_BD_1);
+    else
+      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);     // status empty
+
+
+    if (G_Mixer.chanInput == ch)
+      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3);     // take in progress
+    else
+    if (recorder::active && recorder::canRec(ch))
+      fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4);     // action record
+
+    /* equation for the progress bar:
+     * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */
+
+    int pos = ch->getPosition();
+    if (pos == -1)
+      pos = 0;
+    else
+      pos = (pos * (w()-1)) / (ch->end - ch->begin);
+    fl_rectf(x()+1, y()+1, pos, h()-2, COLOR_BG_2);
+  }
+}
diff --git a/src/gui/elems/ge_status.h b/src/gui/elems/ge_status.h
new file mode 100644 (file)
index 0000000..07e9b28
--- /dev/null
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_status
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_STATUS_H
+#define GE_STATUS_H
+
+
+#include <FL/Fl_Box.H>
+#include "../../core/sampleChannel.h"
+#include "ge_mixed.h"
+
+
+class gStatus : public Fl_Box
+{
+public:
+       gStatus(int X, int Y, int W, int H, class SampleChannel *ch, const char *L=0);
+       void draw();
+       class SampleChannel *ch;
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_waveTools.cpp b/src/gui/elems/ge_waveTools.cpp
new file mode 100644 (file)
index 0000000..d7712c1
--- /dev/null
@@ -0,0 +1,103 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gg_waveTools
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "../../core/graphics.h"
+#include "../../core/mixer.h"
+#include "../elems/ge_mixed.h"
+#include "../elems/ge_waveform.h"
+#include "ge_waveTools.h"
+
+
+gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l)
+       : Fl_Scroll(x, y, w, h, l)
+{
+       type(Fl_Scroll::HORIZONTAL_ALWAYS);
+       hscrollbar.color(COLOR_BG_0);
+       hscrollbar.selection_color(COLOR_BG_1);
+       hscrollbar.labelcolor(COLOR_BD_1);
+       hscrollbar.slider(G_BOX);
+
+       waveform = new gWaveform(x, y, w, h-24, ch);
+
+
+       //resizable(waveform);
+}
+
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveTools::updateWaveform() 
+{
+       waveform->alloc(w());
+       waveform->redraw();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveTools::resize(int x, int y, int w, int h) 
+{
+       if (this->w() == w || (this->w() != w && this->h() != h)) {   // vertical or both resize
+               Fl_Widget::resize(x, y, w, h);
+               waveform->resize(x, y, waveform->w(), h-24);
+               updateWaveform();
+       }
+       else {                                                        // horizontal resize
+               Fl_Widget::resize(x, y, w, h);
+       }
+
+       if (this->w() > waveform->w())
+               waveform->stretchToWindow();
+
+       int offset = waveform->x() + waveform->w() - this->w() - this->x();
+       if (offset < 0)
+               waveform->position(waveform->x()-offset, this->y());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWaveTools::handle(int e) 
+{
+       int ret = Fl_Group::handle(e);
+       switch (e) {
+               case FL_MOUSEWHEEL: {
+                       waveform->setZoom(Fl::event_dy());
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
diff --git a/src/gui/elems/ge_waveTools.h b/src/gui/elems/ge_waveTools.h
new file mode 100644 (file)
index 0000000..51cbc65
--- /dev/null
@@ -0,0 +1,49 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gg_waveTools
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GE_WAVETOOLS_H
+#define GE_WAVETOOLS_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Scroll.H>
+
+
+class gWaveTools : public Fl_Scroll {
+public:
+       class gWaveform *waveform;
+
+       gWaveTools(int X,int Y,int W, int H, class SampleChannel *ch, const char *L=0);
+       void resize(int x, int y, int w, int h);
+       int  handle(int e);
+
+       void updateWaveform();
+};
+
+#endif
diff --git a/src/gui/elems/ge_waveform.cpp b/src/gui/elems/ge_waveform.cpp
new file mode 100644 (file)
index 0000000..52cf539
--- /dev/null
@@ -0,0 +1,838 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_waveform
+ * an element which represents a waveform.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/Fl_Menu_Item.H>
+#include <FL/Fl_Menu_Button.H>
+#include <samplerate.h>
+#include "../../core/wave.h"
+#include "../../core/conf.h"
+#include "../../core/mixer.h"
+#include "../../core/waveFx.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../glue/glue.h"
+#include "../dialogs/gd_editor.h"
+#include "ge_waveTools.h"
+#include "ge_mixed.h"
+#include "ge_waveform.h"
+
+
+extern Mixer G_Mixer;
+extern Conf  G_Conf;
+
+
+gWaveform::gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l)
+: Fl_Widget(x, y, w, h, l),
+  chan(ch),
+  menuOpen(false),
+  chanStart(0),
+  chanStartLit(false),
+  chanEnd(0),
+  chanEndLit(false),
+  ratio(0.0f),
+  selectionA(0),
+  selectionB(0),
+  selectionA_abs(0),
+  selectionB_abs(0)
+{
+  data.sup  = NULL;
+  data.inf  = NULL;
+  data.size = 0;
+
+  grid.snap  = G_Conf.sampleEditorGridOn;
+  grid.level = G_Conf.sampleEditorGridVal;
+  
+  stretchToWindow();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gWaveform::~gWaveform() 
+{
+  freeData();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::freeData() 
+{
+  if (data.sup != NULL) {
+    free(data.sup);
+    free(data.inf);
+    data.sup  = NULL;
+    data.inf  = NULL;
+    data.size = 0;
+  }
+  grid.points.clear();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWaveform::alloc(int datasize)
+{
+  ratio = chan->wave->size / (float) datasize;
+
+  if (ratio < 2)
+    return 0;
+
+  freeData();
+
+  data.size = datasize;
+  data.sup  = (int*) malloc(data.size * sizeof(int));
+  data.inf  = (int*) malloc(data.size * sizeof(int));
+
+  int offset = h() / 2;
+  int zero   = y() + offset; // center, zero amplitude (-inf dB)
+
+  /* grid frequency: store a grid point every 'gridFreq' pixel. Must be
+   * even, as always */
+
+  int gridFreq = 0;
+  if (grid.level != 0) {
+    gridFreq = chan->wave->size / grid.level; 
+    if (gridFreq % 2 != 0)
+      gridFreq--;
+  }
+
+  for (int i=0; i<data.size; i++) {
+
+    int pp;  // point prev
+    int pn;  // point next
+
+    /* resampling the waveform, hardcore way. Many thanks to
+     * http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html
+     * Note: we use
+     *   p = j * (m-1 / n)
+     * instead of
+     *   p = j * (m-1 / n-1)
+     * in order to obtain 'datasize' cells to parse (and not datasize-1) */
+
+    pp = i * ((chan->wave->size - 1) / (float) datasize);
+    pn = (i+1) * ((chan->wave->size - 1) / (float) datasize);
+
+    if (pp % 2 != 0) pp -= 1;
+    if (pn % 2 != 0) pn -= 1;
+
+    float peaksup = 0.0f;
+    float peakinf = 0.0f;
+
+    /* scan the original data in chunks */
+
+    int k = pp;
+    while (k < pn) {
+
+      if (chan->wave->data[k] > peaksup)
+        peaksup = chan->wave->data[k];    // FIXME - Left data only
+      else
+      if (chan->wave->data[k] <= peakinf)
+        peakinf = chan->wave->data[k];    // FIXME - Left data only
+
+      /* print grid */
+
+      if (gridFreq != 0)
+        if (k % gridFreq == 0 && k != 0)
+          grid.points.add(i);
+      
+      k += 2;
+    }
+
+    data.sup[i] = zero - (peaksup * chan->boost * offset);
+    data.inf[i] = zero - (peakinf * chan->boost * offset);
+
+    // avoid window overflow
+
+    if (data.sup[i] < y())       data.sup[i] = y();
+    if (data.inf[i] > y()+h()-1) data.inf[i] = y()+h()-1;
+  }
+
+  recalcPoints();
+  return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::recalcPoints() 
+{
+  selectionA = relativePoint(selectionA_abs);
+  selectionB = relativePoint(selectionB_abs);
+  chanStart  = relativePoint(chan->begin / 2);
+
+  /* fix the rounding error when chanEnd is set on the very end of the
+   * sample */
+
+  if (chan->end == chan->wave->size)
+    chanEnd = data.size - 2; // 2 px border
+  else
+    chanEnd = relativePoint(chan->end / 2);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::draw() 
+{
+  /* blank canvas */
+
+  fl_rectf(x(), y(), w(), h(), COLOR_BG_0);
+
+  /* draw selection (if any) */
+
+  if (selectionA != selectionB) {
+
+    int a_x = selectionA + x() - BORDER; // - start;
+    int b_x = selectionB + x() - BORDER; //  - start;
+
+    if (a_x < 0)
+      a_x = 0;
+    if (b_x >= w()-1)
+      b_x = w()-1;
+
+    if (selectionA < selectionB)
+      fl_rectf(a_x+BORDER, y(), b_x-a_x, h(), COLOR_BD_0);
+    else
+      fl_rectf(b_x+BORDER, y(), a_x-b_x, h(), COLOR_BD_0);
+  }
+
+  /* draw waveform from x1 (offset driven by the scrollbar) to x2
+   * (width of parent window). We don't draw the entire waveform,
+   * only the visibile part. */
+
+  int offset = h() / 2;
+  int zero   = y() + offset; // sample zero (-inf dB)
+
+  int wx1 = abs(x() - ((gWaveTools*)parent())->x());
+  int wx2 = wx1 + ((gWaveTools*)parent())->w();
+  if (x()+w() < ((gWaveTools*)parent())->w())
+    wx2 = x() + w() - BORDER;
+
+  fl_color(0, 0, 0);
+  for (int i=wx1; i<wx2; i++) {
+    fl_line(i+x(), zero, i+x(), data.sup[i]);
+    fl_line(i+x(), zero, i+x(), data.inf[i]);
+    
+    /* print grid */
+
+    for (unsigned k=0; k<grid.points.size; k++) {
+      if (grid.points.at(k) == i) {
+        //gLog("draw grid line at %d\n", i);
+        fl_color(fl_rgb_color(54, 54, 54));
+        fl_line_style(FL_DASH, 0, NULL);
+        fl_line(i+x(), y(), i+x(), y()+h());
+        fl_color(0, 0, 0);
+        fl_line_style(FL_SOLID, 0, NULL);
+        break;
+      }
+    }
+  }
+
+  /* border box */
+
+  fl_rect(x(), y(), w(), h(), COLOR_BD_0);
+
+  /* print chanStart */
+
+  int lineX = x()+chanStart+1;
+
+  if (chanStartLit) fl_color(COLOR_BD_1);
+  else              fl_color(COLOR_BD_0);
+
+  /* vertical line */
+
+  fl_line(lineX, y()+1, lineX, y()+h()-2);
+
+  /* print flag and avoid overflow */
+
+  if (lineX+FLAG_WIDTH > w()+x()-2)
+    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
+  else  {
+    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
+    fl_color(255, 255, 255);
+    fl_draw("s", lineX+4, y()+h()-3);
+  }
+
+  /* print chanEnd */
+
+  lineX = x()+chanEnd;
+  if (chanEndLit) fl_color(COLOR_BD_1);
+  else            fl_color(COLOR_BD_0);
+
+  fl_line(lineX, y()+1, lineX, y()+h()-2);
+
+  if (lineX-FLAG_WIDTH < x())
+    fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
+  else {
+    fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
+    fl_color(255, 255, 255);
+    fl_draw("e", lineX-10, y()+10);
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWaveform::handle(int e) 
+{
+  int ret = 0;
+
+  switch (e) {
+
+    case FL_PUSH: {
+
+      mouseX = Fl::event_x();
+      pushed = true;
+
+      if (!mouseOnEnd() && !mouseOnStart()) {
+
+        /* right button? show the menu. Don't set selectionA,B,etc */
+
+        if (Fl::event_button3()) {
+          openEditMenu();
+        }
+        else
+        if (mouseOnSelectionA() || mouseOnSelectionB()) {
+          resized = true;
+        }
+        else {
+          dragged = true;
+          selectionA = Fl::event_x() - x();
+
+          if (selectionA >= data.size) selectionA = data.size;
+
+          selectionB = selectionA;
+          selectionA_abs = absolutePoint(selectionA);
+          selectionB_abs = selectionA_abs;
+        }
+      }
+
+      ret = 1;
+      break;
+    }
+
+    case FL_RELEASE: {
+
+      /* don't recompute points if something is selected */
+
+      if (selectionA != selectionB) {
+        pushed  = false;
+        dragged = false;
+        ret = 1;
+        break;
+      }
+
+      int realChanStart = chan->begin;
+      int realChanEnd   = chan->end;
+
+      if (chanStartLit)
+        realChanStart = absolutePoint(chanStart)*2;
+      else
+      if (chanEndLit)
+        realChanEnd = absolutePoint(chanEnd)*2;
+
+      glue_setBeginEndChannel((gdEditor *) window(), chan, realChanStart, realChanEnd, false);
+
+      pushed  = false;
+      dragged = false;
+
+      redraw();
+      ret = 1;
+      break;
+    }
+
+    case FL_ENTER: {  // enables FL_DRAG
+      ret = 1;
+      break;
+    }
+
+    case FL_LEAVE: {
+      if (chanStartLit || chanEndLit) {
+        chanStartLit = false;
+        chanEndLit   = false;
+        redraw();
+      }
+      ret = 1;
+      break;
+    }
+
+    case FL_MOVE: {
+      mouseX = Fl::event_x();
+      mouseY = Fl::event_y();
+
+      if (mouseOnStart()) {
+        chanStartLit = true;
+        redraw();
+      }
+      else
+      if (chanStartLit) {
+        chanStartLit = false;
+        redraw();
+      }
+
+      if (mouseOnEnd()) {
+        chanEndLit = true;
+        redraw();
+      }
+      else
+      if (chanEndLit) {
+        chanEndLit = false;
+        redraw();
+      }
+
+      if (mouseOnSelectionA())
+        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+      else
+      if (mouseOnSelectionB())
+        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+      else
+        fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+
+      ret = 1;
+      break;
+    }
+
+    case FL_DRAG: {
+
+      /* here the mouse is on the chanStart tool */
+
+      if (chanStartLit && pushed) {
+
+        chanStart = Fl::event_x() - x();
+      
+        if (grid.snap) 
+          chanStart = applySnap(chanStart);
+
+        if (chanStart < 0)
+          chanStart = 0;
+        else
+        if (chanStart >= chanEnd)
+          chanStart = chanEnd-2;
+        
+        redraw();
+      }
+      else
+      if (chanEndLit && pushed) {
+
+        chanEnd = Fl::event_x() - x();
+
+        if (grid.snap) 
+          chanEnd = applySnap(chanEnd);
+
+        if (chanEnd >= data.size - 2)
+          chanEnd = data.size - 2;
+        else
+        if (chanEnd <= chanStart)
+          chanEnd = chanStart + 2;
+
+        redraw();
+      }
+
+      /* here the mouse is on the waveform, i.e. a selection */
+
+      else
+      if (dragged) {
+
+        selectionB = Fl::event_x() - x();
+
+        if (selectionB >= data.size)
+          selectionB = data.size;
+
+        if (selectionB <= 0)
+          selectionB = 0;
+       
+        if (grid.snap)
+          selectionB = applySnap(selectionB);
+
+        selectionB_abs = absolutePoint(selectionB);
+        redraw();
+      }
+
+      /* here the mouse is on a selection boundary i.e. resize */
+      
+      else
+      if (resized) {
+        int pos = Fl::event_x() - x();
+        if (mouseOnSelectionA()) {
+          selectionA     = grid.snap ? applySnap(pos) : pos;
+          selectionA_abs = absolutePoint(selectionA);
+        }
+        else
+        if (mouseOnSelectionB()) {
+          selectionB     = grid.snap ? applySnap(pos) : pos;
+          selectionB_abs = absolutePoint(selectionB);
+        }
+        redraw();
+      }
+      mouseX = Fl::event_x();
+      ret = 1;
+      break;
+    }
+  }
+  return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+/* pixel snap disances (10px) must be equal to those defined in 
+ * gWaveform::mouseOnSelectionA() and gWaverfrom::mouseOnSelectionB() */
+/* TODO - use constant for 10px */
+
+int gWaveform::applySnap(int pos)
+{
+  for (unsigned i=0; i<grid.points.size; i++) {
+    if (pos >= grid.points.at(i) - 10 &&
+        pos <= grid.points.at(i) + 10)
+    {
+      return grid.points.at(i);
+    }
+  }
+  return pos;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gWaveform::mouseOnStart() 
+{
+  return mouseX-10 >  chanStart + x() - BORDER              &&
+         mouseX-10 <= chanStart + x() - BORDER + FLAG_WIDTH &&
+         mouseY    >  h() + y() - FLAG_HEIGHT;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gWaveform::mouseOnEnd() 
+{
+  return mouseX-10 >= chanEnd + x() - BORDER - FLAG_WIDTH &&
+         mouseX-10 <= chanEnd + x() - BORDER              &&
+         mouseY    <= y() + FLAG_HEIGHT + 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+/* pixel boundaries (10px) must be equal to the snap factor distance
+ * defined in gWaveform::applySnap() */
+
+bool gWaveform::mouseOnSelectionA() 
+{
+  if (selectionA == selectionB)
+    return false;
+  return mouseX >= selectionA-10+x() && mouseX <= selectionA+10+x();
+}
+
+
+bool gWaveform::mouseOnSelectionB() 
+{
+  if (selectionA == selectionB)
+    return false;
+  return mouseX >= selectionB-10+x() && mouseX <= selectionB+10+x();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWaveform::absolutePoint(int p) 
+{
+  if (p <= 0)
+    return 0;
+
+  if (p > data.size)
+    return chan->wave->size / 2;
+
+  return (p * ratio) / 2;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWaveform::relativePoint(int p) 
+{
+  return (ceilf(p / ratio)) * 2;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::openEditMenu() 
+{
+  if (selectionA == selectionB)
+    return;
+
+  menuOpen = true;
+
+  Fl_Menu_Item menu[] = {
+    {"Cut"},
+    {"Trim"},
+    {"Silence"},
+    {"Fade in"},
+    {"Fade out"},
+    {"Smooth edges"},
+    {"Set start/end here"},
+    {0}
+  };
+
+  if (chan->status == STATUS_PLAY) {
+    menu[0].deactivate();
+    menu[1].deactivate();
+  }
+
+  Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+  b->box(G_BOX);
+  b->textsize(11);
+  b->textcolor(COLOR_TEXT_0);
+  b->color(COLOR_BG_0);
+
+  const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+  if (!m) {
+    menuOpen = false;
+    return;
+  }
+
+  /* straightSel() to ensure that point A is always lower than B */
+
+  straightSel();
+
+  if (strcmp(m->label(), "Silence") == 0) {
+    wfx_silence(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
+
+    selectionA = 0;
+    selectionB = 0;
+
+    stretchToWindow();
+    redraw();
+    menuOpen = false;
+    return;
+  }
+
+  if (strcmp(m->label(), "Set start/end here") == 0) {
+
+    glue_setBeginEndChannel(
+        (gdEditor *) window(), // parent
+        chan,
+        absolutePoint(selectionA) * 2,  // stereo!
+        absolutePoint(selectionB) * 2,  // stereo!
+        false, // no recalc (we do it here)
+        false  // don't check
+        );
+
+    selectionA     = 0;
+    selectionB     = 0;
+    selectionA_abs = 0;
+    selectionB_abs = 0;
+
+    recalcPoints();
+    redraw();
+    menuOpen = false;
+    return;
+  }
+
+  if (strcmp(m->label(), "Cut") == 0) {
+    wfx_cut(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
+
+    /* for convenience reset start/end points */
+
+    glue_setBeginEndChannel(
+      (gdEditor *) window(),
+      chan,
+      0,
+      chan->wave->size,
+      false);
+
+    selectionA     = 0;
+    selectionB     = 0;
+    selectionA_abs = 0;
+    selectionB_abs = 0;
+
+    setZoom(0);
+
+    menuOpen = false;
+    return;
+  }
+
+  if (strcmp(m->label(), "Trim") == 0) {
+    wfx_trim(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
+
+    glue_setBeginEndChannel(
+      (gdEditor *) window(),
+      chan,
+      0,
+      chan->wave->size,
+      false);
+
+    selectionA     = 0;
+    selectionB     = 0;
+    selectionA_abs = 0;
+    selectionB_abs = 0;
+
+    stretchToWindow();
+    menuOpen = false;
+    redraw();
+    return;
+  }
+
+  if (!strcmp(m->label(), "Fade in") || !strcmp(m->label(), "Fade out")) {
+
+    int type = !strcmp(m->label(), "Fade in") ? 0 : 1;
+    wfx_fade(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB), type);
+
+    selectionA = 0;
+    selectionB = 0;
+
+    stretchToWindow();
+    redraw();
+    menuOpen = false;
+    return;
+  }
+
+  if (!strcmp(m->label(), "Smooth edges")) {
+
+    wfx_smooth(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB));
+
+    selectionA = 0;
+    selectionB = 0;
+
+    stretchToWindow();
+    redraw();
+    menuOpen = false;
+    return;
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::straightSel() 
+{
+  if (selectionA > selectionB) {
+    unsigned tmp = selectionB;
+    selectionB = selectionA;
+    selectionA = tmp;
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::setZoom(int type) 
+{
+  int newSize;
+  if (type == -1) newSize = data.size*2;  // zoom in
+  else            newSize = data.size/2;  // zoom out
+
+  if (alloc(newSize)) {
+    size(data.size, h());
+
+    /* zoom to pointer */
+
+    int shift;
+    if (x() > 0)
+      shift = Fl::event_x() - x();
+    else
+    if (type == -1)
+      shift = Fl::event_x() + abs(x());
+    else
+      shift = (Fl::event_x() + abs(x())) / -2;
+
+    if (x() - shift > BORDER)
+      shift = 0;
+
+    position(x() - shift, y());
+
+
+    /* avoid overflow when zooming out with scrollbar like that:
+     * |----------[scrollbar]|
+     *
+     * offset vs smaller:
+     * |[wave------------| offset > 0  smaller = false
+     * |[wave----]       | offset < 0, smaller = true
+     * |-------------]   | offset < 0, smaller = false  */
+
+    int  parentW = ((gWaveTools*)parent())->w();
+    int  thisW   = x() + w() - BORDER;           // visible width, not full width
+
+    if (thisW < parentW)
+      position(x() + parentW - thisW, y());
+    if (smaller())
+      stretchToWindow();
+
+    redraw();
+  }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::stretchToWindow() 
+{
+  int s = ((gWaveTools*)parent())->w();
+  alloc(s);
+  position(BORDER, y());
+  size(s, h());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gWaveform::smaller() 
+{
+  return w() < ((gWaveTools*)parent())->w();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWaveform::setGridLevel(int l)
+{
+  grid.points.clear();  
+  grid.level = l;
+  alloc(data.size);
+  redraw();
+}
diff --git a/src/gui/elems/ge_waveform.h b/src/gui/elems/ge_waveform.h
new file mode 100644 (file)
index 0000000..45abd5b
--- /dev/null
@@ -0,0 +1,194 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_waveform
+ * an element which represents a waveform.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GE_WAVEFORM_H
+#define GE_WAVEFORM_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include <FL/fl_draw.H>
+#include <math.h>
+#include "../../utils/utils.h"
+
+
+#define  FLAG_WIDTH  14
+#define  FLAG_HEIGHT 12
+#define  BORDER      8                         // window border <-> widget border
+
+
+class gWaveform : public Fl_Widget {
+
+private:
+
+       /* data
+        * real graphic stuff from the underlying waveform */
+       
+       struct data {
+               int *sup;
+               int *inf;
+               int  size;
+       } data;
+
+       /* grid */
+
+       struct grid {
+               bool snap;
+               int  level;
+               gVector<int> points;
+       } grid;
+
+       /* chan
+        * chan in use. */
+
+       class SampleChannel *chan;
+
+       /* menuOpen
+        * is the menu open? */
+
+       bool menuOpen;
+
+       /* mouseOnStart/end
+        * is mouse on start or end flag? */
+
+       bool mouseOnStart();
+       bool mouseOnEnd();
+
+       /* mouseOnSelectionA/B
+        * as above, for the selection */
+
+       bool mouseOnSelectionA();
+       bool mouseOnSelectionB();
+
+       /* absolutePoint
+        * from a relative 'p' point (zoom affected) returns the same point
+        * zoom 1:1 based */
+
+       int absolutePoint(int p);
+
+       /* relativePoint
+        * from an absolute 'p' point (1:1 zoom), returns the same point zoom
+        * affected */
+
+       int relativePoint(int p);
+
+       /* straightSel
+        * helper function which flattens the selection if it was made from
+        * right to left (inverse selection) */
+
+       void straightSel();
+
+       /* freeData
+        * destroy any graphical buffer */
+
+       void freeData();
+
+       /* smaller
+        * is the waveform smaller than the parent window? */
+
+       bool smaller();
+
+  /* applySnap
+   * snap a point at 'pos' pixel */
+
+  int applySnap(int pos);
+
+public:
+
+       gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0);
+       ~gWaveform();
+       void draw();
+       int  handle(int e);
+
+       /* alloc
+        * allocate memory for the picture */
+
+       int alloc(int datasize=0);
+
+       /* recalcPoints
+        * re-calc chanStart, chanEnd, ... */
+
+       void recalcPoints();
+
+       /* openEditMenu
+        * show edit menu on right-click */
+       
+       void openEditMenu();
+
+       /* displayRatio
+        * how much of the waveform is being displayed on screen */
+
+       inline float displayRatio() { return 1.0f / (data.size / (float) w()); };
+
+       /* zoom
+        * type == 1 : zoom out, type == -1: zoom in */
+
+       void setZoom(int type);
+
+       /* strecthToWindow
+        * shrink or enlarge the waveform to match parent's width (gWaveTools) */
+
+       void stretchToWindow();
+       
+       /* setGridLevel
+        * set a new frequency level for the grid. 0 means disabled. */
+
+       void setGridLevel(int l);
+
+  inline void setSnap(bool v) { grid.snap = v; }
+  inline bool getSnap()       { return grid.snap; }
+    
+       inline int getSize() { return data.size; }
+
+       int  chanStart;
+       bool chanStartLit;
+       int  chanEnd;
+       bool chanEndLit;
+       bool pushed;
+       bool dragged;
+       bool resized;
+
+       float ratio;
+  
+  /* TODO - useless! use Fl::mouse_x() and Fl::mouse_y() instead */
+       int  mouseX;                                     // mouse pos for drag.n.drop
+       int  mouseY;
+
+       /* selectionA/B  = portion of the selected wave
+        * " " "" " _abs = selectionA/B not affected by zoom */
+       /** TODO - change selectionA to selectionA_rel
+           TODO - change selectionB to selectionB_rel */
+       int selectionA;
+       int selectionB;
+       int selectionA_abs;
+       int selectionB_abs;
+};
+
+
+#endif
diff --git a/src/gui/elems/ge_window.cpp b/src/gui/elems/ge_window.cpp
new file mode 100644 (file)
index 0000000..5d4763b
--- /dev/null
@@ -0,0 +1,183 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_window
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include "ge_window.h"
+#include "../../utils/log.h"
+
+
+gWindow::gWindow(int x, int y, int w, int h, const char *title, int id)
+       : Fl_Double_Window(x, y, w, h, title), id(id), parent(NULL) { }
+
+
+/* ------------------------------------------------------------------ */
+
+
+gWindow::gWindow(int w, int h, const char *title, int id)
+       : Fl_Double_Window(w, h, title), id(id), parent(NULL) { }
+
+
+/* ------------------------------------------------------------------ */
+
+
+gWindow::~gWindow() {
+
+       /* delete all subwindows in order to empty the stack */
+
+       for (unsigned i=0; i<subWindows.size; i++)
+               delete subWindows.at(i);
+       subWindows.clear();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+/* this is the default callback of each window, fired when the user closes
+ * the window with the 'x'. Watch out: is the parent that calls delSubWIndow */
+
+void gWindow::cb_closeChild(Fl_Widget *v, void *p) {
+       gWindow *child = (gWindow*) v;
+       if (child->getParent() != NULL)
+               (child->getParent())->delSubWindow(child);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::addSubWindow(gWindow *w) {
+
+       /** TODO - useless: delete ---------------------------------------- */
+       for (unsigned i=0; i<subWindows.size; i++)
+               if (w->getId() == subWindows.at(i)->getId()) {
+                       //gLog("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId());
+                       delete w;
+                       return;
+               }
+       /** --------------------------------------------------------------- */
+
+       w->setParent(this);
+       w->callback(cb_closeChild); // you can pass params: w->callback(cb_closeChild, (void*)params)
+       subWindows.add(w);
+       //debug();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::delSubWindow(gWindow *w) {
+       for (unsigned i=0; i<subWindows.size; i++)
+               if (w->getId() == subWindows.at(i)->getId()) {
+                       delete subWindows.at(i);
+                       subWindows.del(i);
+                       //debug();
+                       return;
+               }
+       //debug();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::delSubWindow(int id) {
+       for (unsigned i=0; i<subWindows.size; i++)
+               if (subWindows.at(i)->getId() == id) {
+                       delete subWindows.at(i);
+                       subWindows.del(i);
+                       //debug();
+                       return;
+               }
+       //debug();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int gWindow::getId() {
+       return id;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::setId(int id) {
+       this->id = id;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::debug() {
+       gLog("---- window stack (id=%d): ----\n", getId());
+       for (unsigned i=0; i<subWindows.size; i++)
+               gLog("[gWindow] %p (id=%d)\n", (void*)subWindows.at(i), subWindows.at(i)->getId());
+       gLog("----\n");
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gWindow *gWindow::getParent() {
+       return parent;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gWindow::setParent(gWindow *w) {
+       parent = w;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gWindow::hasWindow(int id) {
+       for (unsigned i=0; i<subWindows.size; i++)
+               if (id == subWindows.at(i)->getId())
+                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+gWindow *gWindow::getChild(int id) {
+       for (unsigned i=0; i<subWindows.size; i++)
+               if (id == subWindows.at(i)->getId())
+                       return subWindows.at(i);
+       return NULL;
+}
diff --git a/src/gui/elems/ge_window.h b/src/gui/elems/ge_window.h
new file mode 100644 (file)
index 0000000..74b5254
--- /dev/null
@@ -0,0 +1,73 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_window
+ * A custom window.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef __GE_WINDOW_H__
+#define __GE_WINDOW_H__
+
+
+#include <FL/Fl_Double_Window.H>
+#include "../../utils/utils.h"
+
+
+class gWindow : public Fl_Double_Window {
+
+protected:
+       gVector <gWindow *> subWindows;
+       int id;
+       gWindow *parent;
+
+public:
+       gWindow(int x, int y, int w, int h, const char *title=0, int id=0);
+       gWindow(int w, int h, const char *title=0, int id=0);
+       ~gWindow();
+
+       static void cb_closeChild(Fl_Widget *v, void *p);
+
+       void addSubWindow(gWindow *w);
+       void delSubWindow(gWindow *w);
+       void delSubWindow(int id);
+
+       int  getId();
+       void setId(int id);
+       void debug();
+
+       void     setParent(gWindow *);
+       gWindow *getParent();
+       gWindow *getChild(int id);
+
+       /* hasWindow
+        * true if the window with id 'id' exists in the stack. */
+
+       bool hasWindow(int id);
+
+};
+
+
+#endif
diff --git a/src/gui_utils.cpp b/src/gui_utils.cpp
deleted file mode 100644 (file)
index 4c3ffa7..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gui_utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "mixer.h"
-#include "patch.h"
-#include "gui_utils.h"
-#include "graphics.h"
-#include "gd_warnings.h"
-#include "ge_window.h"
-#include "ge_channel.h"
-#include "gd_mainWindow.h"
-#include "gg_keyboard.h"
-#include "gd_actionEditor.h"
-#include "recorder.h"
-#include "wave.h"
-#include "pluginHost.h"
-#include "channel.h"
-#include "log.h"
-#include "conf.h"
-
-
-extern Mixer          G_Mixer;
-extern unsigned      G_beats;
-extern bool                 G_audio_status;
-extern Patch         G_patch;
-extern Conf          G_conf;
-extern uint32_t      G_time;
-extern gdMainWindow *mainWin;
-#ifdef WITH_VST
-extern PluginHost               G_PluginHost;
-#endif
-
-
-static int blinker = 0;
-
-
-void gu_refresh()
-{
-       Fl::lock();
-
-       /* update dynamic elements: in and out meters, beat meter and
-        * each channel */
-
-       mainWin->inOut->refresh();
-       mainWin->beatMeter->redraw();
-       mainWin->keyboard->refreshColumns();
-
-       /* compute timer for blinker */
-
-       blinker++;
-       if (blinker > 12)
-               blinker = 0;
-
-       /* redraw GUI */
-
-       Fl::unlock();
-       Fl::awake();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gu_getBlinker()
-{
-       return blinker;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_updateControls()
-{
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               G_Mixer.channels.at(i)->guiChannel->update();
-
-       mainWin->inOut->setOutVol(G_Mixer.outVol);
-       mainWin->inOut->setInVol(G_Mixer.inVol);
-#ifdef WITH_VST
-       mainWin->inOut->setMasterFxOutFull(G_PluginHost.masterOut.size > 0);
-       mainWin->inOut->setMasterFxInFull(G_PluginHost.masterIn.size > 0);
-#endif
-
-       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
-       mainWin->timing->setBpm(G_Mixer.bpm);
-
-       /* if you reset to init state while the seq is in play: it's better to
-        * update the button status */
-
-       mainWin->controller->updatePlay(G_Mixer.running);
-       mainWin->controller->updateMetronome(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_update_win_label(const char *c)
-{
-       std::string out = VERSIONE_STR;
-       out += " - ";
-       out += c;
-       mainWin->copy_label(out.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_setFavicon(Fl_Window *w)
-{
-#if defined(__linux__)
-       fl_open_display();
-       Pixmap p, mask;
-       XpmCreatePixmapFromData(
-               fl_display,
-               DefaultRootWindow(fl_display),
-               (char **)giada_icon,
-               &p,
-               &mask,
-               NULL);
-       w->icon((char *)p);
-#elif defined(_WIN32)
-       w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_openSubWindow(gWindow *parent, gWindow *child, int id)
-{
-       if (parent->hasWindow(id)) {
-               gLog("[GU] parent has subwindow with id=%d, deleting\n", id);
-               parent->delSubWindow(id);
-       }
-       child->setId(id);
-       parent->addSubWindow(child);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_refreshActionEditor()
-{
-       /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */
-
-       gdActionEditor *aeditor = (gdActionEditor*) mainWin->getChild(WID_ACTION_EDITOR);
-       if (aeditor) {
-               Channel *chan = aeditor->chan;
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
-               gu_openSubWindow(mainWin, new gdActionEditor(chan), WID_ACTION_EDITOR);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gWindow *gu_getSubwindow(gWindow *parent, int id)
-{
-       if (parent->hasWindow(id))
-               return parent->getChild(id);
-       else
-               return NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_closeAllSubwindows()
-{
-       /* don't close WID_FILE_BROWSER, because it's the caller of this
-        * function */
-
-       mainWin->delSubWindow(WID_ACTION_EDITOR);
-       mainWin->delSubWindow(WID_SAMPLE_EDITOR);
-       mainWin->delSubWindow(WID_FX_LIST);
-       mainWin->delSubWindow(WID_FX);
-}
diff --git a/src/gui_utils.h b/src/gui_utils.h
deleted file mode 100644 (file)
index 80c873c..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gui_utils
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GUI_UTILS_H
-#define GUI_UTILS_H
-
-#include <dirent.h>
-#include <string>
-#include <FL/x.H>
-#include <FL/Fl.H>
-#ifdef __APPLE__
-       #include <libgen.h>     // in osx, for basename() (but linux?)
-#endif
-
-/* including stuff for the favicon (or whatever called) */
-
-#if defined(_WIN32)
-       #include "resource.h"
-#elif defined(__linux__)
-       #include <X11/xpm.h>
-#endif
-
-
-/* refresh
- * refresh all GUI elements. */
-
-void gu_refresh();
-
-/* getBlinker
-*  return blinker value, used to make widgets blink. */
-
-int gu_getBlinker();
-
-/* updateControls
- * update attributes of control elements (sample names, volumes, ...).
- * Useful when loading a new patch. */
-
-void gu_updateControls();
-
-/* update_win_label
- * update the name of the main window */
-
-void gu_update_win_label(const char *c);
-
-void gu_setFavicon(Fl_Window *w);
-
-void gu_openSubWindow(class gWindow *parent, gWindow *child, int id);
-
-/* refreshActionEditor
- * reload the action editor window by closing and reopening it. It's used
- * when you delete some actions from the mainWindow and the action editor
- * window is open. */
-
-void gu_refreshActionEditor();
-
-
-/* closeAllSubwindows
- * close all subwindows attached to mainWin. */
-
-void gu_closeAllSubwindows();
-
-
-/* getSubwindow
- * return a pointer to an open subwindow, otherwise NULL. */
-
-gWindow *gu_getSubwindow(class gWindow *parent, int id);
-
-#endif
diff --git a/src/init.cpp b/src/init.cpp
deleted file mode 100644 (file)
index beeab04..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * init
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <ctime>
-#include "init.h"
-#include "log.h"
-#include "mixer.h"
-#include "wave.h"
-#include "const.h"
-#include "utils.h"
-#include "mixerHandler.h"
-#include "patch.h"
-#include "conf.h"
-#include "pluginHost.h"
-#include "recorder.h"
-#include "midiMapConf.h"
-#include "gd_mainWindow.h"
-#include "gui_utils.h"
-#include "gd_warnings.h"
-#include "kernelMidi.h"
-
-
-extern Mixer                      G_Mixer;
-extern bool                               G_audio_status;
-extern bool                               G_quit;
-extern Patch              G_Patch;
-extern Conf          G_Conf;
-extern MidiMapConf   G_MidiMap;
-extern gdMainWindow *mainWin;
-
-#ifdef WITH_VST
-extern PluginHost         G_PluginHost;
-#endif
-
-
-void init_prepareParser()
-{
-       G_Conf.read();
-       G_Patch.setDefault();
-       if (!gLog_init(G_Conf.logMode))
-               gLog("[init] log init failed! Using default stdout\n");
-  time_t t;
-  time (&t);
-       gLog("[init] Giada "VERSIONE" - %s", ctime(&t));
-       gLog("[init] configuration file ready\n");
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_prepareKernelAudio()
-{
-       kernelAudio::openDevice(
-               G_Conf.soundSystem,
-               G_Conf.soundDeviceOut,
-               G_Conf.soundDeviceIn,
-               G_Conf.channelsOut,
-               G_Conf.channelsIn,
-               G_Conf.samplerate,
-               G_Conf.buffersize);
-       G_Mixer.init();
-       recorder::init();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_prepareKernelMIDI()
-{
-       kernelMidi::setApi(G_Conf.midiSystem);
-       kernelMidi::openOutDevice(G_Conf.midiPortOut);
-       kernelMidi::openInDevice(G_Conf.midiPortIn);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_prepareMidiMap()
-{
-       G_MidiMap.init();
-       G_MidiMap.setDefault();
-       G_MidiMap.readMap(G_Conf.midiMapPath);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_startGUI(int argc, char **argv)
-{
-       char win_label[32];
-       sprintf(win_label, "%s - %s",
-                                       VERSIONE_STR,
-                                       !strcmp(G_Patch.name, "") ? "(default patch)" : G_Patch.name);
-
-       mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv);
-       mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH);
-
-       /* never update the GUI elements if G_audio_status is bad, segfaults
-        * are around the corner */
-
-       if (G_audio_status)
-               gu_updateControls();
-
-       if (!G_audio_status)
-               gdAlert(
-                       "Your soundcard isn't configured correctly.\n"
-                       "Check the configuration and restart Giada."
-               );
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_startKernelAudio()
-{
-       if (G_audio_status)
-               kernelAudio::startStream();
-
-#ifdef WITH_VST
-       G_PluginHost.allocBuffers();
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_shutdown()
-{
-       G_quit = true;
-
-       /* store position and size of the main window for the next startup */
-
-       G_Conf.mainWindowX = mainWin->x();
-       G_Conf.mainWindowY = mainWin->y();
-       G_Conf.mainWindowW = mainWin->w();
-       G_Conf.mainWindowH = mainWin->h();
-
-       /* close any open subwindow, especially before cleaning PluginHost to
-        * avoid mess */
-
-       gu_closeAllSubwindows();
-       gLog("[init] all subwindows closed\n");
-
-       /* write configuration file */
-
-       if (!G_Conf.write())
-               gLog("[init] error while saving configuration file!\n");
-       else
-               gLog("[init] configuration saved\n");
-
-       /* if G_audio_status we close the kernelAudio FIRST, THEN the mixer.
-        * The opposite could cause random segfaults (even now with RtAudio?). */
-
-       if (G_audio_status) {
-               kernelAudio::closeDevice();
-               G_Mixer.close();
-               gLog("[init] Mixer closed\n");
-       }
-
-       recorder::clearAll();
-       gLog("[init] Recorder cleaned up\n");
-
-#ifdef WITH_VST
-       G_PluginHost.freeAllStacks();
-       gLog("[init] Plugin Host cleaned up\n");
-#endif
-
-       gLog("[init] Giada "VERSIONE" closed\n\n");
-       gLog_close();
-}
diff --git a/src/init.h b/src/init.h
deleted file mode 100644 (file)
index 0824f65..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * init
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef INIT_H
-#define INIT_H
-
-
-#include <cstdio>
-#include <stdint.h>
-#ifdef __APPLE__
-       #include <pwd.h>
-#endif
-
-
-void init_prepareParser();
-void init_startGUI(int argc, char **argv);
-void init_prepareKernelAudio();
-void init_prepareKernelMIDI();
-void init_prepareMidiMap();
-void init_startKernelAudio();
-void init_shutdown();
-
-
-#endif
diff --git a/src/kernelAudio.cpp b/src/kernelAudio.cpp
deleted file mode 100644 (file)
index 094422c..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * KernelAudio
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <vector>
-#include "kernelAudio.h"
-#include "mixer.h"
-#include "glue.h"
-#include "conf.h"
-#include "log.h"
-
-
-extern Mixer G_Mixer;
-extern Conf  G_Conf;
-extern bool     G_audio_status;
-
-
-namespace kernelAudio {
-
-RtAudio  *system       = NULL;
-unsigned  numDevs      = 0;
-bool             inputEnabled = 0;
-unsigned  realBufsize  = 0;
-int       api          = 0;
-
-int openDevice(
-       int _api,
-       int outDev,
-       int inDev,
-       int outChan,
-       int inChan,
-       int samplerate,
-       int buffersize)
-{
-       api = _api;
-       gLog("[KA] using system 0x%x\n", api);
-#if defined(__linux__)
-       if (api == SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
-               system = new RtAudio(RtAudio::UNIX_JACK);
-       else
-       if (api == SYS_API_ALSA && hasAPI(RtAudio::LINUX_ALSA))
-               system = new RtAudio(RtAudio::LINUX_ALSA);
-       else
-       if (api == SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
-               system = new RtAudio(RtAudio::LINUX_PULSE);
-#elif defined(_WIN32)
-       if (api == SYS_API_DS && hasAPI(RtAudio::WINDOWS_DS))
-               system = new RtAudio(RtAudio::WINDOWS_DS);
-       else
-       if (api == SYS_API_ASIO && hasAPI(RtAudio::WINDOWS_ASIO))
-               system = new RtAudio(RtAudio::WINDOWS_ASIO);
-#elif defined(__APPLE__)
-       if (api == SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE))
-               system = new RtAudio(RtAudio::MACOSX_CORE);
-#endif
-       else {
-               G_audio_status = false;
-               return 0;
-       }
-
-
-
-       //gLog("[KA] %d\n", sizeof(system->rtapi_));
-
-       gLog("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate);
-
-       numDevs = system->getDeviceCount();
-
-       if (numDevs < 1) {
-               gLog("[KA] no devices found with this API\n");
-               closeDevice();
-               G_audio_status = false;
-               return 0;
-       }
-       else {
-               gLog("[KA] %d device(s) found\n", numDevs);
-               for (unsigned i=0; i<numDevs; i++)
-                       gLog("  %d) %s\n", i, getDeviceName(i));
-       }
-
-
-       RtAudio::StreamParameters outParams;
-       RtAudio::StreamParameters inParams;
-
-       if (outDev == DEFAULT_SOUNDDEV_OUT)
-               outParams.deviceId = getDefaultOut();
-       else
-               outParams.deviceId = outDev;
-       outParams.nChannels = 2;
-       outParams.firstChannel = outChan*2; // chan 0=0, 1=2, 2=4, ...
-
-       /* inDevice can be disabled */
-
-       if (inDev != -1) {
-               inParams.deviceId     = inDev;
-               inParams.nChannels    = 2;
-               inParams.firstChannel = inChan*2;   // chan 0=0, 1=2, 2=4, ...
-               inputEnabled = true;
-       }
-       else
-               inputEnabled = false;
-
-
-  RtAudio::StreamOptions options;
-  options.streamName = "Giada";
-  options.numberOfBuffers = 4;
-
-       realBufsize = buffersize;
-
-#if defined(__linux__) || defined(__APPLE__)
-       if (api == SYS_API_JACK) {
-               samplerate = getFreq(outDev, 0);
-               gLog("[KA] JACK in use, freq = %d\n", samplerate);
-               G_Conf.samplerate = samplerate;
-       }
-#endif
-
-       try {
-               if (inDev != -1) {
-                       system->openStream(
-                               &outParams,                                     // output params
-                               &inParams,                                      // input params
-                               RTAUDIO_FLOAT32,                        // audio format
-                               samplerate,                                     // sample rate
-                               &realBufsize,                           // buffer size in byte
-                               &G_Mixer.masterPlay,  // audio callback
-                               NULL,                                                                   // user data (unused)
-                               &options);
-               }
-               else {
-                       system->openStream(
-                               &outParams,                                     // output params
-                               NULL,                                   // input params
-                               RTAUDIO_FLOAT32,                        // audio format
-                               samplerate,                                     // sample rate
-                               &realBufsize,                           // buffer size in byte
-                               &G_Mixer.masterPlay,  // audio callback
-                               NULL,                                                                   // user data (unused)
-                               &options);
-               }
-               G_audio_status = true;
-
-#if defined(__linux__)
-               if (api == SYS_API_JACK)
-                       jackSetSyncCb();
-#endif
-
-               return 1;
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] system init error: %s\n", e.getMessage().c_str());
-               closeDevice();
-               G_audio_status = false;
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int startStream() {
-       try {
-               system->startStream();
-               gLog("[KA] latency = %lu\n", system->getStreamLatency());
-               return 1;
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] Start stream error: %s\n", e.getMessage().c_str());
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int stopStream() {
-       try {
-               system->stopStream();
-               return 1;
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] Stop stream error\n");
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-const char *getDeviceName(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).name.c_str();
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] invalid device ID = %d\n", dev);
-               return NULL;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int closeDevice() {
-       if (system->isStreamOpen()) {
-#if defined(__linux__) || defined(__APPLE__)
-               system->abortStream(); // stopStream seems to lock the thread
-#elif defined(_WIN32)
-               system->stopStream();    // on Windows it's the opposite
-#endif
-               system->closeStream();
-               delete system;
-               system = NULL;
-       }
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-unsigned getMaxInChans(int dev) {
-
-       if (dev == -1) return 0;
-
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).inputChannels;
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] Unable to get input channels\n");
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-unsigned getMaxOutChans(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).outputChannels;
-       }
-       catch (RtAudioError &e) {
-               gLog("[KA] Unable to get output channels\n");
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool isProbed(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).probed;
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-unsigned getDuplexChans(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).duplexChannels;
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool isDefaultIn(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultInput;
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool isDefaultOut(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultOutput;
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int getTotalFreqs(unsigned dev) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.size();
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int    getFreq(unsigned dev, int i) {
-       try {
-               return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.at(i);
-       }
-       catch (RtAudioError &e) {
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int getDefaultIn() {
-       return system->getDefaultInputDevice();
-}
-
-int getDefaultOut() {
-       return system->getDefaultOutputDevice();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int    getDeviceByName(const char *name) {
-       for (unsigned i=0; i<numDevs; i++)
-               if (strcmp(name, getDeviceName(i))==0)
-                       return i;
-       return -1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool hasAPI(int API) {
-       std::vector<RtAudio::Api> APIs;
-       RtAudio::getCompiledApi(APIs);
-       for (unsigned i=0; i<APIs.size(); i++)
-               if (APIs.at(i) == API)
-                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-std::string getRtAudioVersion() {
-       return RtAudio::getVersion();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-#ifdef __linux__
-#include <jack/jack.h>
-#include <jack/intclient.h>
-#include <jack/transport.h>
-
-jack_client_t *jackGetHandle() {
-       return (jack_client_t*) system->rtapi_->__HACK__getJackClient();
-}
-
-void jackStart() {
-       if (api == SYS_API_JACK) {
-               jack_client_t *client = jackGetHandle();
-               jack_transport_start(client);
-       }
-}
-
-
-void jackStop() {
-       if (api == SYS_API_JACK) {
-               jack_client_t *client = jackGetHandle();
-               jack_transport_stop(client);
-       }
-}
-
-
-void jackSetSyncCb() {
-       jack_client_t *client = jackGetHandle();
-       jack_set_sync_callback(client, jackSyncCb, NULL);
-       //jack_set_sync_timeout(client, 8);
-}
-
-
-int jackSyncCb(jack_transport_state_t state, jack_position_t *pos,
-               void *arg)
-{
-       switch (state) {
-               case JackTransportStopped:
-                       gLog("[KA] Jack transport stopped, frame=%d\n", pos->frame);
-                       glue_stopSeq(false);  // false = not from GUI
-                       if (pos->frame == 0)
-                               glue_rewindSeq();
-                       break;
-
-               case JackTransportRolling:
-                       gLog("[KA] Jack transport rolling\n");
-                       break;
-
-               case JackTransportStarting:
-                       gLog("[KA] Jack transport starting, frame=%d\n", pos->frame);
-                       glue_startSeq(false);  // false = not from GUI
-                       if (pos->frame == 0)
-                               glue_rewindSeq();
-                       break;
-
-               default:
-                       gLog("[KA] Jack transport [unknown]\n");
-       }
-       return 1;
-}
-
-#endif
-
-}
-
-
diff --git a/src/kernelAudio.h b/src/kernelAudio.h
deleted file mode 100644 (file)
index 0d566e8..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * KernelAudio
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef KERNELAUDIO_H
-#define KERNELAUDIO_H
-
-
-#include "rtaudio-mod/RtAudio.h"
-#if defined(__linux__)
-       #include <jack/jack.h>
-       #include <jack/intclient.h>
-       #include <jack/transport.h>
-#endif
-
-
-namespace kernelAudio {
-
-       int openDevice(
-                       int api,
-                       int outDev,
-                       int inDev,
-                       int outChan,
-                       int inChan,
-                       int samplerate,
-                       int buffersize);
-       int closeDevice();
-
-       int startStream();
-       int stopStream();
-
-       bool                      isProbed       (unsigned dev);
-       bool                isDefaultIn    (unsigned dev);
-       bool                      isDefaultOut   (unsigned dev);
-       const char *getDeviceName  (unsigned dev);
-       unsigned    getMaxInChans  (int dev);
-       unsigned    getMaxOutChans (unsigned dev);
-       unsigned    getDuplexChans (unsigned dev);
-       int         getTotalFreqs  (unsigned dev);
-       int                                     getFreq        (unsigned dev, int i);
-       int                                     getDeviceByName(const char *name);
-       int         getDefaultOut  ();
-       int         getDefaultIn   ();
-       bool        hasAPI         (int API);
-
-       std::string getRtAudioVersion();
-
-#ifdef __linux__
-       jack_client_t *jackGetHandle();
-       void jackStart();
-       void jackStop();
-       void jackSetSyncCb();
-       int  jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg);
-#endif
-
-       /* *** how to avoid multiple definition of ***
-        * When you declare a variable in a header file, every source file that
-        * includes that header, either directly or indirectly, gets its own
-        * separate copy of the variable. Then when you go to link all the .o
-        * files together, the linker sees that the variable is instantiated
-        * in a bunch of .o files. Make it extern in the header file and
-        * instantiate it in memory.cpp. */
-
-       extern RtAudio  *system;
-       extern unsigned  numDevs;
-       extern bool              inputEnabled;
-       extern unsigned  realBufsize;           // reale bufsize from the soundcard
-       extern int       api;
-}
-
-#endif
diff --git a/src/kernelMidi.cpp b/src/kernelMidi.cpp
deleted file mode 100644 (file)
index 1d4f99b..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * KernelMidi
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdio.h>
-#include "kernelMidi.h"
-#include "glue.h"
-#include "mixer.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "pluginHost.h"
-#include "conf.h"
-#include "midiMapConf.h"
-#include "log.h"
-
-
-extern bool        G_midiStatus;
-extern Conf        G_Conf;
-extern Mixer       G_Mixer;
-extern MidiMapConf G_MidiMap;
-
-#ifdef WITH_VST
-extern PluginHost  G_PluginHost;
-#endif
-
-
-namespace kernelMidi
-{
-
-int        api         = 0;      // one api for both in & out
-RtMidiOut *midiOut     = NULL;
-RtMidiIn  *midiIn      = NULL;
-unsigned   numOutPorts = 0;
-unsigned   numInPorts  = 0;
-
-cb_midiLearn *cb_learn = NULL;
-void         *cb_data  = NULL;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void startMidiLearn(cb_midiLearn *cb, void *data)
-{
-       cb_learn = cb;
-       cb_data  = data;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void stopMidiLearn()
-{
-       cb_learn = NULL;
-       cb_data  = NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void setApi(int _api)
-{
-       api = api;
-       gLog("[KM] using system 0x%x\n", api);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int openOutDevice(int port)
-{
-       try {
-               midiOut = new RtMidiOut((RtMidi::Api) api, "Giada MIDI Output");
-               G_midiStatus = true;
-  }
-  catch (RtMidiError &error) {
-    gLog("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
-    G_midiStatus = false;
-    return 0;
-  }
-
-       /* print output ports */
-
-       numOutPorts = midiOut->getPortCount();
-  gLog("[KM] %d output MIDI ports found\n", numOutPorts);
-  for (unsigned i=0; i<numOutPorts; i++)
-               gLog("  %d) %s\n", i, getOutPortName(i));
-
-       /* try to open a port, if enabled */
-
-       if (port != -1 && numOutPorts > 0) {
-               try {
-                       midiOut->openPort(port, getOutPortName(port));
-                       gLog("[KM] MIDI out port %d open\n", port);
-
-                       /* for each init command of MidiMap, send the init commands to the
-                       external world. TODO 1 - we shold do that only if there is a map loaded
-                       and available in MidiMap.
-                       TODO 2 - move the map initialization to another function */
-
-                       for(int i=0; i<G_MidiMap.MAX_INIT_COMMANDS; i++) {
-                               if (G_MidiMap.init_messages[i] != 0x0 && G_MidiMap.init_channels[i] != -1) {
-                                       gLog("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", G_MidiMap.init_channels[i], G_MidiMap.init_messages[i]);
-                                       send(G_MidiMap.init_messages[i] | MIDI_CHANS[G_MidiMap.init_channels[i]]);
-                               }
-                       }
-
-                       return 1;
-               }
-               catch (RtMidiError &error) {
-                       gLog("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str());
-                       G_midiStatus = false;
-                       return 0;
-               }
-       }
-       else
-               return 2;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int openInDevice(int port)
-{
-       try {
-               midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input");
-               G_midiStatus = true;
-  }
-  catch (RtMidiError &error) {
-    gLog("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
-    G_midiStatus = false;
-    return 0;
-  }
-
-       /* print input ports */
-
-       numInPorts = midiIn->getPortCount();
-  gLog("[KM] %d input MIDI ports found\n", numInPorts);
-  for (unsigned i=0; i<numInPorts; i++)
-               gLog("  %d) %s\n", i, getInPortName(i));
-
-       /* try to open a port, if enabled */
-
-       if (port != -1 && numInPorts > 0) {
-               try {
-                       midiIn->openPort(port, getInPortName(port));
-                       midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
-                       gLog("[KM] MIDI in port %d open\n", port);
-                       midiIn->setCallback(&callback);
-                       return 1;
-               }
-               catch (RtMidiError &error) {
-                       gLog("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str());
-                       G_midiStatus = false;
-                       return 0;
-               }
-       }
-       else
-               return 2;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool hasAPI(int API)
-{
-       std::vector<RtMidi::Api> APIs;
-       RtMidi::getCompiledApi(APIs);
-       for (unsigned i=0; i<APIs.size(); i++)
-               if (APIs.at(i) == API)
-                       return true;
-       return false;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-const char *getOutPortName(unsigned p)
-{
-       try { return midiOut->getPortName(p).c_str(); }
-       catch (RtMidiError &error) { return NULL; }
-}
-
-const char *getInPortName(unsigned p)
-{
-       try { return midiIn->getPortName(p).c_str(); }
-       catch (RtMidiError &error) { return NULL; }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void send(uint32_t data)
-{
-       if (!G_midiStatus)
-               return;
-
-  std::vector<unsigned char> msg(1, getB1(data));
-  msg.push_back(getB2(data));
-  msg.push_back(getB3(data));
-
-       midiOut->sendMessage(&msg);
-       gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void send(int b1, int b2, int b3)
-{
-       if (!G_midiStatus)
-               return;
-
-       std::vector<unsigned char> msg(1, b1);
-
-       if (b2 != -1)
-               msg.push_back(b2);
-       if (b3 != -1)
-               msg.push_back(b3);
-
-       midiOut->sendMessage(&msg);
-       //gLog("[KM] send msg=(%X %X %X)\n", b1, b2, b3);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void callback(double t, std::vector<unsigned char> *msg, void *data)
-{
-       /* 0.8.0 - for now we handle other midi signals (common and real-time
-        * messages) as unknown, for debugging purposes */
-
-       if (msg->size() < 3) {
-               gLog("[KM] MIDI received - unkown signal - size=%d, value=0x", (int) msg->size());
-               for (unsigned i=0; i<msg->size(); i++)
-                       gLog("%X", (int) msg->at(i));
-               gLog("\n");
-               return;
-       }
-
-       /* in this place we want to catch two things: a) note on/note off
-        * from a keyboard and b) knob/wheel/slider movements from a
-        * controller */
-
-       uint32_t input = getIValue(msg->at(0), msg->at(1), msg->at(2));
-       uint32_t chan  = input & 0x0F000000;
-       uint32_t value = input & 0x0000FF00;
-       uint32_t pure  = 0x00;
-       if (!G_Conf.noNoteOff)
-               pure  = input & 0xFFFF0000;   // input without 'value' byte
-       else
-               pure  = input & 0xFFFFFF00;   // input with 'value' byte
-
-       gLog("[KM] MIDI received - 0x%X (chan %d)", input, chan >> 24);
-
-       /* start dispatcher. If midi learn is on don't parse channels, just
-        * learn incoming midi signal. Otherwise process master events first,
-        * then each channel in the stack. This way incoming signals don't
-        * get processed by glue_* when midi learning is on. */
-
-       if (cb_learn)   {
-               gLog("\n");
-               cb_learn(pure, cb_data);
-       }
-       else {
-
-               /* process master events */
-
-               if      (pure == G_Conf.midiInRewind) {
-                       gLog(" >>> rewind (global) (pure=0x%X)", pure);
-                       glue_rewindSeq();
-               }
-               else if (pure == G_Conf.midiInStartStop) {
-                       gLog(" >>> startStop (global) (pure=0x%X)", pure);
-                       glue_startStopSeq();
-               }
-               else if (pure == G_Conf.midiInActionRec) {
-                       gLog(" >>> actionRec (global) (pure=0x%X)", pure);
-                       glue_startStopActionRec();
-               }
-               else if (pure == G_Conf.midiInInputRec) {
-                       gLog(" >>> inputRec (global) (pure=0x%X)", pure);
-                       glue_startStopInputRec(false, false);   // update gui, no popup messages
-               }
-               else if (pure == G_Conf.midiInMetronome) {
-                       gLog(" >>> metronome (global) (pure=0x%X)", pure);
-                       glue_startStopMetronome(false);
-               }
-               else if (pure == G_Conf.midiInVolumeIn) {
-                       float vf = (value >> 8)/127.0f;
-                       gLog(" >>> input volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
-                       glue_setInVol(vf, false);
-               }
-               else if (pure == G_Conf.midiInVolumeOut) {
-                       float vf = (value >> 8)/127.0f;
-                       gLog(" >>> output volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
-                       glue_setOutVol(vf, false);
-               }
-               else if (pure == G_Conf.midiInBeatDouble) {
-                       gLog(" >>> sequencer x2 (global) (pure=0x%X)", pure);
-                       glue_beatsMultiply();
-               }
-               else if (pure == G_Conf.midiInBeatHalf) {
-                       gLog(" >>> sequencer /2 (global) (pure=0x%X)", pure);
-                       glue_beatsDivide();
-               }
-
-               /* process channels */
-
-               for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-
-                       Channel *ch = (Channel*) G_Mixer.channels.at(i);
-
-                       if (!ch->midiIn) continue;
-
-                       if      (pure == ch->midiInKeyPress) {
-                               gLog(" >>> keyPress, ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_keyPress(ch, false, false);
-                       }
-                       else if (pure == ch->midiInKeyRel) {
-                               gLog(" >>> keyRel ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_keyRelease(ch, false, false);
-                       }
-                       else if (pure == ch->midiInMute) {
-                               gLog(" >>> mute ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_setMute(ch, false);
-                       }
-                       else if (pure == ch->midiInSolo) {
-                               gLog(" >>> solo ch=%d (pure=0x%X)", ch->index, pure);
-                               ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false);
-                       }
-                       else if (pure == ch->midiInVolume) {
-                               float vf = (value >> 8)/127.0f;
-                               gLog(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
-                               glue_setChanVol(ch, vf, false);
-                       }
-                       else if (pure == ((SampleChannel*)ch)->midiInPitch) {
-                               float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0]
-                               gLog(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
-                               glue_setPitch(NULL, (SampleChannel*)ch, vf, false);
-                       }
-                       else if (pure == ((SampleChannel*)ch)->midiInReadActions) {
-                               gLog(" >>> start/stop read actions ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_startStopReadingRecs((SampleChannel*)ch, false);
-                       }
-               }
-               gLog("\n");
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string getRtMidiVersion()
-{
-       return midiOut->getVersion();
-}
-
-
-}  // namespace
diff --git a/src/kernelMidi.h b/src/kernelMidi.h
deleted file mode 100644 (file)
index d446995..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * KernelMidi
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef KERNELMIDI_H
-#define KERNELMIDI_H
-
-
-#include <stdint.h>
-#include <RtMidi.h>
-#include "channel.h"
-
-
-namespace kernelMidi {
-
-       extern int      api;      // one api for both in & out
-       extern unsigned numOutPorts;
-       extern unsigned numInPorts;
-
-       typedef void (cb_midiLearn) (uint32_t, void *);
-
-       /* cb_learn
-        * callback prepared by the gdMidiGrabber window and called by
-        * kernelMidi. It contains things to do once the midi message has been
-        * stored. */
-
-       extern cb_midiLearn *cb_learn;
-       extern void         *cb_data;
-
-       void startMidiLearn(cb_midiLearn *cb, void *data);
-       void stopMidiLearn();
-
-       inline int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; }
-       inline int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; }
-       inline int getB3(uint32_t iValue) { return (iValue >> 8)  & 0xFF; }
-
-       inline uint32_t getIValue(int b1, int b2, int b3) {
-               return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00);
-       }
-
-       /* send
-        * send a MIDI message 's' (uint32_t). */
-
-       void send(uint32_t s);
-
-       /* send (2)
-        * send separate bytes of MIDI message. */
-
-       void send(int b1, int b2=-1, int b3=-1);
-
-       /* setApi
-        * set the Api in use for both in & out messages. */
-
-       void setApi(int api);
-
-       /* open/close/in/outDevice */
-
-       int openOutDevice(int port);
-       int openInDevice(int port);
-       int closeInDevice();
-       int closeOutDevice();
-
-       /* getIn/OutPortName
-        * return the name of the port 'p'. */
-
-       const char *getInPortName(unsigned p);
-       const char *getOutPortName(unsigned p);
-
-       bool hasAPI(int API);
-
-       /* callback
-        * master callback for input events. */
-
-       void callback(double t, std::vector<unsigned char> *msg, void *data);
-
-       std::string getRtMidiVersion();
-}
-
-#endif
diff --git a/src/log.cpp b/src/log.cpp
deleted file mode 100644 (file)
index 0f5be34..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * log
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <cstdio>
-#include <cstdarg>
-#include <string>
-#include "log.h"
-#include "const.h"
-#include "utils.h"
-
-
-static FILE *f;
-static int   mode;
-static bool  stat;
-
-
-int gLog_init(int m) {
-       mode = m;
-       stat = true;
-       if (mode == LOG_MODE_FILE) {
-               std::string fpath = gGetHomePath() + "/giada.log";
-               f = fopen(fpath.c_str(), "a");
-               if (!f) {
-                       stat = false;
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLog_close() {
-       if (mode == LOG_MODE_FILE)
-               fclose(f);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLog(const char *format, ...) {
-       if (mode == LOG_MODE_MUTE)
-               return;
-  va_list args;
-  va_start(args, format);
-  if (mode == LOG_MODE_FILE && stat == true)
-               vfprintf(f, format, args);
-  else
-               vprintf(format, args);
-  va_end(args);
-}
diff --git a/src/log.h b/src/log.h
deleted file mode 100644 (file)
index c53f9c7..0000000
--- a/src/log.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * log
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __LOG_H__
-#define __LOG_H__
-
-
-/* init
- * init logger. Mode defines where to write the output: LOG_MODE_STDOUT,
- * LOG_MODE_FILE and LOG_MODE_MUTE. */
-int  gLog_init (int mode);
-
-void gLog_close();
-
-void gLog(const char *format, ...);
-
-
-#endif
index e714162a88701544d7f83d6847b673e77d9605f0..a70c61616f450e7e24032c130673b8f90e4350e7 100644 (file)
 #if defined(__linux__) || defined(__APPLE__)
        #include <unistd.h>
 #endif
-#include "init.h"
-#include "const.h"
-#include "patch.h"
-#include "conf.h"
-#include "midiMapConf.h"
-#include "mixer.h"
-#include "mixerHandler.h"
-#include "kernelAudio.h"
-#include "recorder.h"
-#include "gui_utils.h"
-#include "gd_mainWindow.h"
+#include "core/init.h"
+#include "core/const.h"
+#include "core/patch.h"
+#include "core/conf.h"
+#include "core/midiMapConf.h"
+#include "core/mixer.h"
+#include "core/mixerHandler.h"
+#include "core/kernelAudio.h"
+#include "core/recorder.h"
+#include "utils/gui_utils.h"
+#include "gui/dialogs/gd_mainWindow.h"
 #ifdef WITH_VST
-#include "pluginHost.h"
+#include "core/pluginHost.h"
 #endif
 
 
diff --git a/src/midiChannel.cpp b/src/midiChannel.cpp
deleted file mode 100644 (file)
index 6f38684..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "channel.h"
-#include "midiChannel.h"
-#include "pluginHost.h"
-#include "patch.h"
-#include "conf.h"
-#include "kernelMidi.h"
-#include "log.h"
-
-
-extern Patch       G_Patch;
-extern Mixer       G_Mixer;
-extern Conf        G_Conf;
-#ifdef WITH_VST
-extern PluginHost  G_PluginHost;
-#endif
-
-
-MidiChannel::MidiChannel(int bufferSize)
-       : Channel    (CHANNEL_MIDI, STATUS_OFF, bufferSize),
-         midiOut    (false),
-         midiOutChan(MIDI_CHANS[0])
-{
-#ifdef WITH_VST // init VstEvents stack
-       freeVstMidiEvents(true);
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-MidiChannel::~MidiChannel() {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-void MidiChannel::freeVstMidiEvents(bool init)
-{
-       if (events.numEvents == 0 && !init)
-               return;
-       memset(events.events, 0, sizeof(VstEvent*) * MAX_VST_EVENTS);
-       events.numEvents = 0;
-       events.reserved  = 0;
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-void MidiChannel::addVstMidiEvent(uint32_t msg)
-{
-       addVstMidiEvent(G_PluginHost.createVstMidiEvent(msg));
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-void MidiChannel::addVstMidiEvent(VstMidiEvent *e)
-{
-       if (events.numEvents < MAX_VST_EVENTS) {
-               events.events[events.numEvents] = (VstEvent*) e;
-               events.numEvents++;
-               /*
-               gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n",
-                       events.numEvents,
-                       e->deltaFrames,
-                       e->midiData[0],
-                       e->midiData[1],
-                       e->midiData[2]
-               );*/
-       }
-       else
-               gLog("[MidiChannel] channel %d VstEvents = %d > MAX_VST_EVENTS, nothing to do\n", index, events.numEvents);
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::onBar(int frame) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::stop() {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::empty() {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::quantize(int index, int localFrame, int globalFrame) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef WITH_VST
-
-VstEvents *MidiChannel::getVstEvents()
-{
-       return (VstEvents *) &events;
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
-{
-       if (a->type == ACTION_MIDI)
-               sendMidi(a, localFrame/2);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::onZero(int frame)
-{
-       if (status == STATUS_ENDING) {
-               status = STATUS_OFF;
-               sendMidiLplay();
-       }
-       else
-       if (status == STATUS_WAIT) {
-               status = STATUS_PLAY;
-               sendMidiLplay();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::setMute(bool internal)
-{
-       mute = true;    // internal mute does not exist for midi (for now)
-       if (midiOut)
-               kernelMidi::send(MIDI_ALL_NOTES_OFF);
-#ifdef WITH_VST
-               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
-#endif
-       sendMidiLmute();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::unsetMute(bool internal)
-{
-       mute = false;   // internal mute does not exist for midi (for now)
-       sendMidiLmute();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::process(float *buffer)
-{
-#ifdef WITH_VST
-       G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
-       freeVstMidiEvents();
-#endif
-
-       for (int j=0; j<bufferSize; j+=2) {
-               buffer[j]   += vChan[j]   * volume; // * panLeft;   future?
-               buffer[j+1] += vChan[j+1] * volume; // * panRight;  future?
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::start(int frame, bool doQuantize)
-{
-       switch (status) {
-               case STATUS_PLAY:
-                       status = STATUS_ENDING;
-                       sendMidiLplay();
-                       break;
-               case STATUS_ENDING:
-               case STATUS_WAIT:
-                       status = STATUS_OFF;
-                       sendMidiLplay();
-                       break;
-               case STATUS_OFF:
-                       status = STATUS_WAIT;
-                       sendMidiLplay();
-                       break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::stopBySeq()
-{
-       kill(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::kill(int frame)
-{
-       if (status & (STATUS_PLAY | STATUS_ENDING)) {
-               if (midiOut)
-                       kernelMidi::send(MIDI_ALL_NOTES_OFF);
-#ifdef WITH_VST
-               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
-#endif
-       }
-       status = STATUS_OFF;
-       sendMidiLplay();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int MidiChannel::loadByPatch(const char *f, int i)
-{
-       volume      = G_Patch.getVol(i);
-       index       = G_Patch.getIndex(i);
-       mute        = G_Patch.getMute(i);
-       mute_s      = G_Patch.getMute_s(i);
-       solo        = G_Patch.getSolo(i);
-       panLeft     = G_Patch.getPanLeft(i);
-       panRight    = G_Patch.getPanRight(i);
-
-       midiOut     = G_Patch.getMidiValue(i, "Out");
-       midiOutChan = G_Patch.getMidiValue(i, "OutChan");
-
-       readPatchMidiIn(i);
-       readPatchMidiOut(i);
-
-       return SAMPLE_LOADED_OK;  /// TODO - change name, it's meaningless here
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::sendMidi(recorder::action *a, int localFrame)
-{
-       if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
-               if (midiOut)
-                       kernelMidi::send(a->iValue | MIDI_CHANS[midiOutChan]);
-
-#ifdef WITH_VST
-               a->event->deltaFrames = localFrame;
-               addVstMidiEvent(a->event);
-#endif
-       }
-}
-
-
-void MidiChannel::sendMidi(uint32_t data)
-{
-       if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
-               if (midiOut)
-                       kernelMidi::send(data | MIDI_CHANS[midiOutChan]);
-#ifdef WITH_VST
-               addVstMidiEvent(data);
-#endif
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::rewind()
-{
-       if (midiOut)
-               kernelMidi::send(MIDI_ALL_NOTES_OFF);
-#ifdef WITH_VST
-               addVstMidiEvent(MIDI_ALL_NOTES_OFF);
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiChannel::writePatch(FILE *fp, int i, bool isProject)
-{
-       Channel::writePatch(fp, i, isProject);
-
-       fprintf(fp, "chanMidiOut%d=%u\n",        i, midiOut);
-       fprintf(fp, "chanMidiOutChan%d=%u\n",    i, midiOutChan);
-}
diff --git a/src/midiChannel.h b/src/midiChannel.h
deleted file mode 100644 (file)
index e6e1a09..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * channel
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef MIDI_CHANNEL_H
-#define MIDI_CHANNEL_H
-
-
-#ifdef WITH_VST
-
-/* before including aeffetx(x).h we must define __cdecl, otherwise VST
- * headers can't be compiled correctly. In windows __cdecl is already
- * defined. */
-
-       #ifdef __GNUC__
-               #ifndef _WIN32
-                       #define __cdecl
-               #endif
-       #endif
-       #include "vst/aeffectx.h"
-
-#endif
-
-
-class MidiChannel : public Channel {
-
-public:
-
-       MidiChannel(int bufferSize);
-       ~MidiChannel();
-
-  bool    midiOut;           // enable midi output
-  uint8_t midiOutChan;       // midi output channel
-
-       void  process    (float *buffer);
-       void  start      (int frame, bool doQuantize);
-       void  kill       (int frame);
-       void  empty      ();
-       void  stopBySeq  ();
-       void  stop       ();
-       void  rewind     ();
-       void  setMute    (bool internal);
-       void  unsetMute  (bool internal);
-       int   loadByPatch(const char *file, int i);
-       void  writePatch (FILE *fp, int i, bool isProject);
-       void  quantize   (int index, int localFrame, int globalFrame);
-       void  onZero     (int frame);
-       void  onBar      (int frame);
-       void  parseAction(recorder::action *a, int localFrame, int globalFrame);
-
-       /* ---------------------------------------------------------------- */
-
-       /* sendMidi
-        * send Midi event to the outside world. */
-
-       void sendMidi(recorder::action *a, int localFrame);
-       void sendMidi(uint32_t data);
-
-#ifdef WITH_VST
-
-       /* getVstEvents
-        * return a pointer to gVstEvents. */
-
-       VstEvents *getVstEvents();
-
-       /* freeVstMidiEvents
-        * empty vstEvents structure. Init: use the method for channel
-        * initialization. */
-
-       void freeVstMidiEvents(bool init=false);
-
-       /* addVstMidiEvent
-        * take a composite MIDI event, decompose it and add it to channel. The
-        * other version creates a VstMidiEvent on the fly. */
-
-       void addVstMidiEvent(struct VstMidiEvent *e);
-       void addVstMidiEvent(uint32_t msg);
-
-#endif
-
-       /* ---------------------------------------------------------------- */
-
-#ifdef WITH_VST
-
-       /* VST struct containing MIDI events. When ready, events are sent to
-        * each plugin in the channel.
-        *
-        * Anatomy of VstEvents
-        * --------------------
-        *
-        * VstInt32  numEvents = number of Events in array
-        * VstIntPtr reserved  = zero (Reserved for future use)
-        * VstEvent *events[n] = event pointer array, variable size
-        *
-        * Note that by default VstEvents only holds three events- if you want
-        * it to hold more, create an equivalent struct with a larger array,
-        * and then cast it to a VstEvents object when you've populated it.
-        * That's what we do with gVstEvents! */
-
-       struct gVstEvents {
-    VstInt32  numEvents;
-    VstIntPtr reserved;
-    VstEvent *events[MAX_VST_EVENTS];
-       } events;
-
-#endif
-
-};
-
-
-#endif
diff --git a/src/midiMapConf.cpp b/src/midiMapConf.cpp
deleted file mode 100644 (file)
index 7fa8268..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * midiMapConf
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdlib.h>
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <dirent.h>
-#include "midiMapConf.h"
-#include "const.h"
-#include "utils.h"
-#include "log.h"
-
-
-using std::string;
-
-
-void MidiMapConf::init()
-{
-       midimapsPath = gGetHomePath() + "/midimaps/";
-
-       /* scan dir of midi maps and load the filenames into <>maps. */
-
-       gLog("[MidiMapConf::init] scanning midimaps directory...\n");
-
-  DIR    *dp;
-  dirent *ep;
-  dp = opendir(midimapsPath.c_str());
-
-       if (!dp) {
-               gLog("[MidiMapConf::init] unable to scan midimaps directory!\n");
-               return;
-       }
-
-       while ((ep = readdir(dp))) {
-               if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
-                       continue;
-
-               // TODO - check if is a valid midimap file (verify headers)
-
-               gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name);
-
-               maps.add(ep->d_name);
-       }
-
-       closedir(dp);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiMapConf::setDefault()
-{
-       brand  = "";
-       device = "";
-
-       for (int i=0; i<MAX_INIT_COMMANDS; i++) {
-               init_channels[i] = -1;
-               init_messages[i] = 0x00;
-       }
-
-       muteOnChan     = 0;
-       muteOnOffset   = 0;
-       muteOnMsg      = 0;
-
-       muteOffChan    = 0;
-       muteOffOffset  = 0;
-       muteOffMsg     = 0;
-
-       soloOnChan     = 0;
-       soloOnOffset   = 0;
-       soloOnMsg      = 0;
-
-       soloOffChan    = 0;
-       soloOffOffset  = 0;
-       soloOffMsg     = 0;
-
-       waitingChan    = 0;
-       waitingOffset  = 0;
-       waitingMsg     = 0;
-
-       playingChan    = 0;
-       playingOffset  = 0;
-       playingMsg     = 0;
-
-       stoppingChan   = 0;
-       stoppingOffset = 0;
-       stoppingMsg    = 0;
-
-       stoppedChan    = 0;
-       stoppedOffset  = 0;
-       stoppedMsg     = 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int MidiMapConf::readMap(string file)
-{
-       if (file.empty()) {
-               gLog("[MidiMapConf::readFromFile] midimap not specified, nothing to do\n");
-               return 0;
-       }
-
-       gLog("[MidiMapConf::readFromFile] reading midimap file '%s'\n", file.c_str());
-
-       string path = midimapsPath + file;
-       fp = fopen(path.c_str(), "r");
-       if (!fp) {
-               gLog("[MidiMapConf::readFromFile] unreadable midimap file\n");
-               return 0;
-       }
-
-       brand  = getValue("brand");
-       device = getValue("device");
-
-       gLog("[MidiMapConf::readFromFile] reading midimap for %s %s\n",
-                       brand.c_str(), device.c_str());
-
-       /* parse init commands */
-
-       gVector<string> ic;
-       gSplit(getValue("init_commands"), ";", &ic);
-       for (unsigned i=0; i<MAX_INIT_COMMANDS && i<ic.size; i++) {
-               sscanf(ic.at(i).c_str(), "%d:%x", &init_channels[i], &init_messages[i]);
-               gLog("[MidiMapConf::readFromFile] init command %d - channel %d - message 0x%X\n",
-                               i, init_channels[i], init_messages[i]);
-       }
-
-       /* parse messages */
-
-       parse("mute_on",  &muteOnChan,   &muteOnMsg,   &muteOnOffset);
-       parse("mute_off", &muteOffChan,  &muteOffMsg,  &muteOffOffset);
-       parse("solo_on",  &soloOnChan,   &soloOnMsg,   &soloOnOffset);
-       parse("solo_off", &soloOffChan,  &soloOffMsg,  &soloOffOffset);
-       parse("waiting",  &waitingChan,  &waitingMsg,  &waitingOffset);
-       parse("playing",  &playingChan,  &playingMsg,  &playingOffset);
-       parse("stopping", &stoppingChan, &stoppingMsg, &stoppingOffset);
-       parse("stopped",  &stoppedChan,  &stoppedMsg,  &stoppedOffset);
-
-       close();
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiMapConf::close()
-{
-       if (fp != NULL)
-               fclose(fp);
-       fp = NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void MidiMapConf::parse(string key, int *chan, uint32_t *msg, int *offset)
-{
-       gLog("[MidiMapConf::parse2] command %s - ", key.c_str());
-       string value = getValue(key.c_str());
-
-       /* grab channel part, i.e. [channel]:*/
-
-       *chan = atoi(value.substr(0, value.find(':')).c_str());
-
-       /* grab MIDI part :[midi-message] and search for 'nn' note placeholder within.
-        * Note: when using 'string::npos' as the value for a len (or sublen)
-        * parameter in string's member functions, means "until the end of the
-        * string". */
-
-       string midiParts = value.substr(value.find(':')+3, string::npos);
-
-       char strmsg[MAX_MIDI_NIBBLES];
-       *offset = 0;
-
-       /* build the message as a string, for each char (i.e. nibble) in the
-        * original string. Substitute 'n' with zeros. */
-
-       for (unsigned i=0, p=24; i<MAX_MIDI_NIBBLES; i++, p-=4) {
-               if (midiParts[i] == 'n') {
-                       strmsg[i] = '0';
-                       if (*offset == 0)
-                               *offset = p;
-               }
-               else
-                       strmsg[i] = midiParts[i];
-       }
-
-       *msg = strtoul(strmsg, NULL, 16);  // from string to uint32_t
-
-       gLog("chan=%d value=%s msg=%#x, offset=%d\n", *chan, midiParts.c_str(), *msg, *offset);
-}
diff --git a/src/midiMapConf.h b/src/midiMapConf.h
deleted file mode 100644 (file)
index 3ff65fa..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * midiMapConf
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef __MIDIMAPCONF_H__
-#define __MIDIMAPCONF_H__
-
-
-#include <limits.h>
-#include <stdint.h>
-#include "dataStorage.h"
-#include "utils.h"
-#if defined(__APPLE__)
-#include <pwd.h>
-#endif
-
-
-using std::string;
-
-
-class MidiMapConf : public DataStorage
-{
-private:
-
-       void close();
-       void parse(string key, int *chan, uint32_t *msg, int *offset);
-
-public:
-
-       static const int MAX_INIT_COMMANDS = 32;
-       static const int MAX_MIDI_BYTES = 4;
-       static const int MAX_MIDI_NIBBLES = 8;
-
-       /* midimapsPath
-        * path of midimap files, different between OSes. */
-
-       string midimapsPath;
-
-       /* maps
-        * Maps are the available .giadamap files. Each element of the vector
-        * represents a .giadamap filename. */
-
-       gVector<string> maps;
-
-       string brand;
-       string device;
-
-       /* init_*
-        * init_commands. These messages are sent to the physical device as a wake up
-        * signal. */
-
-       int      init_channels[MAX_INIT_COMMANDS];
-       uint32_t init_messages[MAX_INIT_COMMANDS];
-
-       /* events
-        * [event]Channel: the MIDI output channel to send the event to
-        * [event]notePos: the byte where the note is stored ('nn' placeholder)
-        * [event]offset:  the note offset (i.e. of 'nn' placeholder) */
-
-       int      muteOnChan;
-       int      muteOnOffset;
-       uint32_t muteOnMsg;
-
-       int      muteOffChan;
-       int      muteOffOffset;
-       uint32_t muteOffMsg;
-
-       int      soloOnChan;
-       int      soloOnOffset;
-       uint32_t soloOnMsg;
-
-       int      soloOffChan;
-       int      soloOffOffset;
-       uint32_t soloOffMsg;
-
-       int      waitingChan;
-       int      waitingOffset;
-       uint32_t waitingMsg;
-
-       int      playingChan;
-       int      playingOffset;
-       uint32_t playingMsg;
-
-       int      stoppingChan;
-       int      stoppingOffset;
-       uint32_t stoppingMsg;
-
-       int      stoppedChan;
-       int      stoppedOffset;
-       uint32_t stoppedMsg;
-
-       /* init
-       Parse the midi maps folders and find the available maps. */
-
-       void init();
-
-       /* setDefault
-       Set default values in case no maps are available/choosen. */
-
-       void setDefault();
-
-       /* readMap
-       Read a midi map from file 'file'. */
-
-       int readMap(string file);
-};
-
-#endif
diff --git a/src/mixer.cpp b/src/mixer.cpp
deleted file mode 100644 (file)
index 4c25065..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * mixer
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <math.h>
-#include "mixer.h"
-#include "init.h"
-#include "wave.h"
-#include "gui_utils.h"
-#include "recorder.h"
-#include "pluginHost.h"
-#include "patch.h"
-#include "conf.h"
-#include "mixerHandler.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "kernelMidi.h"
-#include "log.h"
-
-
-extern Mixer                    G_Mixer;
-extern Patch                    G_Patch;
-extern Conf                             G_Conf;
-#ifdef WITH_VST
-extern PluginHost  G_PluginHost;
-#endif
-
-
-Mixer::Mixer()         {}
-Mixer::~Mixer() {}
-
-
-#define TICKSIZE 38
-
-
-float Mixer::tock[TICKSIZE] = {
-        0.059033,  0.117240,  0.173807,  0.227943,  0.278890,  0.325936,
-        0.368423,  0.405755,  0.437413,  0.462951,  0.482013,  0.494333,
-        0.499738,  0.498153,  0.489598,  0.474195,  0.452159,  0.423798,
-        0.389509,  0.349771,  0.289883,  0.230617,  0.173194,  0.118739,
-        0.068260,  0.022631, -0.017423, -0.051339,     -0.078721, -0.099345,
-       -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
-       -0.070862, -0.048844
-};
-
-
-float Mixer::tick[TICKSIZE] = {
-         0.175860,  0.341914,  0.488904,  0.608633,  0.694426,  0.741500,
-         0.747229,  0.711293,  0.635697,  0.524656,  0.384362,  0.222636,
-         0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
-        -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
-        -0.201360, -0.067752,  0.052194,  0.151746,  0.226280,  0.273493,
-         0.293425,  0.288307,  0.262252,  0.220811,  0.170435,  0.117887,
-         0.069639,  0.031320
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::init() {
-       quanto      = 1;
-       docross     = false;
-       rewindWait  = false;
-       running     = false;
-       ready       = true;
-       waitRec     = 0;
-       actualFrame = 0;
-       bpm                 = DEFAULT_BPM;
-       bars                = DEFAULT_BARS;
-       beats               = DEFAULT_BEATS;
-       quantize    = DEFAULT_QUANTIZE;
-       metronome   = false;
-
-       tickTracker = 0;
-       tockTracker = 0;
-       tickPlay    = false;
-       tockPlay    = false;
-
-       outVol       = DEFAULT_OUT_VOL;
-       inVol        = DEFAULT_IN_VOL;
-       peakOut      = 0.0f;
-       peakIn       = 0.0f;
-       chanInput    = NULL;
-       inputTracker = 0;
-
-       actualBeat    = 0;
-
-       midiTCstep    = 0;
-       midiTCrate    = (G_Conf.samplerate / G_Conf.midiTCfps) * 2;  // dealing with stereo vals
-       midiTCframes  = 0;
-       midiTCseconds = 0;
-       midiTCminutes = 0;
-       midiTChours   = 0;
-
-       /* alloc virtual input channels. vChanInput malloc is done in
-        * updateFrameBars, because of its variable size */
-       /** TODO - set kernelAudio::realBufsize * 2 as private member */
-
-       vChanInput   = NULL;
-       vChanInToOut = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
-
-       pthread_mutex_init(&mutex_recs, NULL);
-       pthread_mutex_init(&mutex_chans, NULL);
-       pthread_mutex_init(&mutex_plugins, NULL);
-
-       updateFrameBars();
-       rewind();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Channel *Mixer::addChannel(int type) {
-
-       Channel *ch;
-       int bufferSize = kernelAudio::realBufsize*2;
-
-       if (type == CHANNEL_SAMPLE)
-               ch = new SampleChannel(bufferSize);
-       else
-               ch = new MidiChannel(bufferSize);
-
-       while (true) {
-               int lockStatus = pthread_mutex_trylock(&mutex_chans);
-               if (lockStatus == 0) {
-                       channels.add(ch);
-                       pthread_mutex_unlock(&mutex_chans);
-                       break;
-               }
-       }
-
-       ch->index = getNewIndex();
-       gLog("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size);
-       return ch;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Mixer::getNewIndex() {
-
-       /* always skip last channel: it's the last one just added */
-
-       if (channels.size == 1)
-               return 0;
-
-       int index = 0;
-       for (unsigned i=0; i<channels.size-1; i++) {
-               if (channels.at(i)->index > index)
-                       index = channels.at(i)->index;
-               }
-       index += 1;
-       return index;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Mixer::deleteChannel(Channel *ch) {
-       int lockStatus;
-       while (true) {
-               lockStatus = pthread_mutex_trylock(&mutex_chans);
-               if (lockStatus == 0) {
-                       channels.del(ch);
-                       delete ch;
-                       pthread_mutex_unlock(&mutex_chans);
-                       return 1;
-               }
-               //else
-               //      gLog("[mixer::deleteChannel] waiting for mutex...\n");
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Channel *Mixer::getChannelByIndex(int index) {
-       for (unsigned i=0; i<channels.size; i++)
-               if (channels.at(i)->index == index)
-                       return channels.at(i);
-       gLog("[mixer::getChannelByIndex] channel at index %d not found!\n", index);
-       return NULL;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::sendMIDIsync() {
-
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
-               if (actualFrame % (framesPerBeat/24) == 0)
-                       kernelMidi::send(MIDI_CLOCK, -1, -1);
-       }
-       else
-       if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
-
-               /* check if a new timecode frame has passed. If so, send MIDI TC
-                * quarter frames. 8 quarter frames, divided in two branches:
-                * 1-4 and 5-8. We check timecode frame's parity: if even, send
-                * range 1-4, if odd send 5-8. */
-
-               if (actualFrame % midiTCrate == 0) {
-
-                       /* frame low nibble
-                        * frame high nibble
-                        * seconds low nibble
-                        * seconds high nibble */
-
-                       if (midiTCframes % 2 == 0) {
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F)  | 0x00, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4)    | 0x10, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4)   | 0x30, -1);
-                       }
-
-                       /* minutes low nibble
-                        * minutes high nibble
-                        * hours low nibble
-                        * hours high nibble SMPTE frame rate */
-
-                       else {
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4)   | 0x50, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F)   | 0x60, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4)     | 0x70, -1);
-                       }
-
-                       midiTCframes++;
-
-                       /* check if total timecode frames are greater than timecode fps:
-                        * if so, a second has passed */
-
-                       if (midiTCframes > G_Conf.midiTCfps) {
-                               midiTCframes = 0;
-                               midiTCseconds++;
-                               if (midiTCseconds >= 60) {
-                                       midiTCminutes++;
-                                       midiTCseconds = 0;
-                                       if (midiTCminutes >= 60) {
-                                               midiTChours++;
-                                               midiTCminutes = 0;
-                                       }
-                               }
-                               //gLog("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes);
-                       }
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::sendMIDIrewind() {
-
-       midiTCframes  = 0;
-       midiTCseconds = 0;
-       midiTCminutes = 0;
-       midiTChours   = 0;
-
-       /* For cueing the slave to a particular start point, Quarter Frame
-        * messages are not used. Instead, an MTC Full Frame message should
-        * be sent. The Full Frame is a SysEx message that encodes the entire
-        * SMPTE time in one message */
-
-       if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
-               kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00);  // send msg on channel 0
-               kernelMidi::send(0x01, 0x01, 0x00);        // hours 0
-               kernelMidi::send(0x00, 0x00, 0x00);        // mins, secs, frames 0
-               kernelMidi::send(MIDI_EOX, -1, -1);        // end of sysex
-       }
-}
-
-/* ------------------------------------------------------------------ */
-
-
-int Mixer::masterPlay(
-       void *out_buf, void *in_buf, unsigned n_frames,
-       double streamTime, RtAudioStreamStatus status, void *userData) {
-       return G_Mixer.__masterPlay(out_buf, in_buf, n_frames);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) {
-
-       if (!ready)
-               return 0;
-
-       float *outBuf = ((float *) out_buf);
-       float *inBuf  = ((float *) in_buf);
-       bufferFrames *= 2;     // stereo
-       peakOut       = 0.0f;  // reset peak calculator
-       peakIn        = 0.0f;  // reset peak calculator
-
-       /* always clean each buffer */
-
-       memset(outBuf, 0, sizeof(float) * bufferFrames);         // out
-       memset(vChanInToOut, 0, sizeof(float) * bufferFrames);   // inToOut vChan
-
-       pthread_mutex_lock(&mutex_chans);
-       for (unsigned i=0; i<channels.size; i++)
-               if (channels.at(i)->type == CHANNEL_SAMPLE)
-                       ((SampleChannel*)channels.at(i))->clear();
-       pthread_mutex_unlock(&mutex_chans);
-
-       for (unsigned j=0; j<bufferFrames; j+=2) {
-
-               if (kernelAudio::inputEnabled) {
-
-                       /* input peak calculation (left chan only so far). */
-
-                       if (inBuf[j] * inVol > peakIn)
-                               peakIn = inBuf[j] * inVol;
-
-                       /* "hear what you're playing" - process, copy and paste the input buffer
-                        * onto the output buffer */
-
-                       if (inToOut) {
-                               vChanInToOut[j]   = inBuf[j]   * inVol;
-                               vChanInToOut[j+1] = inBuf[j+1] * inVol;
-                       }
-               }
-
-               /* operations to do if the sequencer is running:
-                * - compute quantizer
-                * - time check for LOOP_REPEAT
-                * - reset loops at beat 0
-                * - read recorded actions
-                * - reset actualFrame */
-
-               if (running) {
-
-                       /* line in recording */
-
-                       if (chanInput != NULL && kernelAudio::inputEnabled) {
-
-                               /* delay comp: wait until waitRec reaches delayComp. WaitRec
-                                * returns to 0 in mixerHandler, as soon as the recording ends */
-
-                               if (waitRec < G_Conf.delayComp)
-                                       waitRec += 2;
-                               else {
-                                       vChanInput[inputTracker]   += inBuf[j]   * inVol;
-                                       vChanInput[inputTracker+1] += inBuf[j+1] * inVol;
-                                       inputTracker += 2;
-                                       if (inputTracker >= totalFrames)
-                                               inputTracker = 0;
-                               }
-                       }
-
-                       /* quantizer computations: quantize rewind and all channels. */
-
-                       if (quantize > 0 && quanto > 0) {
-                               if (actualFrame % (quanto) == 0) {   // is quanto!
-                                       if (rewindWait) {
-                                               rewindWait = false;
-                                               rewind();
-                                       }
-                                       pthread_mutex_lock(&mutex_chans);
-                                       for (unsigned k=0; k<channels.size; k++)
-                                               channels.at(k)->quantize(k, j, actualFrame);  // j == localFrame
-                                       pthread_mutex_unlock(&mutex_chans);
-                               }
-                       }
-
-                       /* reset LOOP_REPEAT, if a bar has passed */
-
-                       if (actualFrame % framesPerBar == 0 && actualFrame != 0) {
-                               if (metronome)
-                                       tickPlay = true;
-
-                               pthread_mutex_lock(&mutex_chans);
-                               for (unsigned k=0; k<channels.size; k++)
-                                       channels.at(k)->onBar(j);
-                               pthread_mutex_unlock(&mutex_chans);
-                       }
-
-                       /* reset loops on beat 0 */
-
-                       if (actualFrame == 0) {
-                               pthread_mutex_lock(&mutex_chans);
-                               for (unsigned k=0; k<channels.size; k++)
-                                       channels.at(k)->onZero(j);
-                               pthread_mutex_unlock(&mutex_chans);
-                       }
-
-                       /* reading all actions recorded */
-
-                       pthread_mutex_lock(&mutex_recs);
-                       for (unsigned y=0; y<recorder::frames.size; y++) {
-                               if (recorder::frames.at(y) == actualFrame) {
-                                       for (unsigned z=0; z<recorder::global.at(y).size; z++) {
-                                               int index   = recorder::global.at(y).at(z)->chan;
-                                               Channel *ch = getChannelByIndex(index);
-                                               ch->parseAction(recorder::global.at(y).at(z), j, actualFrame);
-                                       }
-                                       break;
-                               }
-                       }
-                       pthread_mutex_unlock(&mutex_recs);
-
-                       /* increase actualFrame */
-
-                       actualFrame += 2;
-
-                       /* if actualFrame > totalFrames the sequencer returns to frame 0,
-                        * beat 0. This must be the last operation. */
-
-                       if (actualFrame > totalFrames) {
-                               actualFrame = 0;
-                               actualBeat  = 0;
-                       }
-                       else
-                       if (actualFrame % framesPerBeat == 0 && actualFrame > 0) {
-                               actualBeat++;
-
-                               /* avoid tick and tock to overlap when a new bar has passed (which
-                                * is also a beat) */
-
-                               if (metronome && !tickPlay)
-                                       tockPlay = true;
-                       }
-
-                       sendMIDIsync();
-
-               } // if (running)
-
-               /* sum channels, CHANNEL_SAMPLE only */
-
-               pthread_mutex_lock(&mutex_chans);
-               for (unsigned k=0; k<channels.size; k++) {
-                       if (channels.at(k)->type == CHANNEL_SAMPLE)
-                               ((SampleChannel*)channels.at(k))->sum(j, running);
-               }
-               pthread_mutex_unlock(&mutex_chans);
-
-               /* metronome play */
-               /** FIXME - move this one after the peak meter calculation */
-
-               if (tockPlay) {
-                       outBuf[j]   += tock[tockTracker];
-                       outBuf[j+1] += tock[tockTracker];
-                       tockTracker++;
-                       if (tockTracker >= TICKSIZE-1) {
-                               tockPlay    = false;
-                               tockTracker = 0;
-                       }
-               }
-               if (tickPlay) {
-                       outBuf[j]   += tick[tickTracker];
-                       outBuf[j+1] += tick[tickTracker];
-                       tickTracker++;
-                       if (tickTracker >= TICKSIZE-1) {
-                               tickPlay    = false;
-                               tickTracker = 0;
-                       }
-               }
-       } // end loop J
-
-
-       /* final loop: sum virtual channels and process plugins. */
-
-       pthread_mutex_lock(&mutex_chans);
-       for (unsigned k=0; k<channels.size; k++)
-               channels.at(k)->process(outBuf);
-       pthread_mutex_unlock(&mutex_chans);
-
-       /* processing fxs master in & out, if any. */
-
-#ifdef WITH_VST
-       pthread_mutex_lock(&mutex_plugins);
-       G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT);
-       G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN);
-       pthread_mutex_unlock(&mutex_plugins);
-#endif
-
-       /* post processing master fx + peak calculation. */
-
-       for (unsigned j=0; j<bufferFrames; j+=2) {
-
-               /* merging vChanInToOut, if enabled */
-
-               if (inToOut) {
-                       outBuf[j]   += vChanInToOut[j];
-                       outBuf[j+1] += vChanInToOut[j+1];
-               }
-
-               outBuf[j]   *= outVol;
-               outBuf[j+1] *= outVol;
-
-               /* computes the peak for the left channel (so far). */
-
-               if (outBuf[j] > peakOut)
-                       peakOut = outBuf[j];
-
-               if (G_Conf.limitOutput) {
-                       if (outBuf[j] > 1.0f)
-                               outBuf[j] = 1.0f;
-                       else if (outBuf[j] < -1.0f)
-                               outBuf[j] = -1.0f;
-
-                       if (outBuf[j+1] > 1.0f)
-                               outBuf[j+1] = 1.0f;
-                       else if (outBuf[j+1] < -1.0f)
-                               outBuf[j+1] = -1.0f;
-               }
-       }
-
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::updateFrameBars() {
-
-       /* seconds ....... total time of play (in seconds) of the whole
-        *                 sequencer. 60 / bpm == how many seconds lasts one bpm
-        * totalFrames ... number of frames in the whole sequencer, x2 because
-        *                                                               it's stereo
-        * framesPerBar .. n. of frames within a bar
-        * framesPerBeat . n. of frames within a beat */
-
-       float seconds     = (60.0f / bpm) * beats;
-       totalFrames       = G_Conf.samplerate * seconds * 2;
-       framesPerBar      = totalFrames / bars;
-       framesPerBeat     = totalFrames / beats;
-       framesInSequencer = framesPerBeat * MAX_BEATS;
-
-       /* big troubles if frames are odd. */
-
-       if (totalFrames % 2 != 0)
-               totalFrames--;
-       if (framesPerBar % 2 != 0)
-               framesPerBar--;
-       if (framesPerBeat % 2 != 0)
-               framesPerBeat--;
-
-       updateQuanto();
-
-       /* realloc input virtual channel, if not NULL. TotalFrames is changed! */
-
-       if (vChanInput != NULL)
-               free(vChanInput);
-       vChanInput = (float*) malloc(totalFrames * sizeof(float));
-       if (!vChanInput)
-               gLog("[Mixer] vChanInput realloc error!\n");
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Mixer::close() {
-       running = false;
-       while (channels.size > 0)
-               deleteChannel(channels.at(0));
-       free(vChanInput);
-       free(vChanInToOut);
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool Mixer::isSilent() {
-       for (unsigned i=0; i<channels.size; i++)
-               if (channels.at(i)->status == STATUS_PLAY)
-                       return false;
-       return true;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::rewind() {
-
-       actualFrame = 0;
-       actualBeat  = 0;
-
-       if (running)
-               for (unsigned i=0; i<channels.size; i++)
-                       channels.at(i)->rewind();
-
-       sendMIDIrewind();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Mixer::updateQuanto() {
-
-       /* big troubles if frames are odd. */
-
-       if (quantize != 0)
-               quanto = framesPerBeat / quantize;
-       if (quanto % 2 != 0)
-               quanto++;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool Mixer::hasLogicalSamples() {
-       for (unsigned i=0; i<channels.size; i++)
-               if (channels.at(i)->type == CHANNEL_SAMPLE)
-                       if (((SampleChannel*)channels.at(i))->wave)
-                               if (((SampleChannel*)channels.at(i))->wave->isLogical)
-                                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool Mixer::hasEditedSamples() {
-       for (unsigned i=0; i<channels.size; i++)
-               if (channels.at(i)->type == CHANNEL_SAMPLE)
-                       if (((SampleChannel*)channels.at(i))->wave)
-                               if (((SampleChannel*)channels.at(i))->wave->isEdited)
-                                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool Mixer::mergeVirtualInput() {
-       if (vChanInput == NULL) {
-               gLog("[Mixer] virtual input channel not alloc'd\n");
-               return false;
-       }
-       else {
-#ifdef WITH_VST
-               G_PluginHost.processStackOffline(vChanInput, PluginHost::MASTER_IN, 0, totalFrames);
-#endif
-               int numFrames = totalFrames*sizeof(float);
-               memcpy(chanInput->wave->data, vChanInput, numFrames);
-               memset(vChanInput, 0, numFrames); // clear vchan
-               return true;
-       }
-}
diff --git a/src/mixer.h b/src/mixer.h
deleted file mode 100644 (file)
index 586bacc..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * mixer
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef MIXER_H
-#define MIXER_H
-
-#include <stdlib.h>
-#include <pthread.h>
-#include "const.h"
-#include "kernelAudio.h"
-#include "utils.h"
-
-
-class Mixer {
-
-public:
-
-       Mixer();
-       ~Mixer();
-
-       void init();
-       int  close();
-
-       /* addChannel
-        * add a new channel without any wave inside of it. */
-
-       class Channel *addChannel(int type);
-
-       /* deleteChannel
-        * completely remove a channel from the stack. */
-
-       int deleteChannel(class Channel *ch);
-
-       /* masterPlay
-        * core method (callback) */
-
-       static int masterPlay(
-               void *out_buf, void *in_buf, unsigned n_frames,
-               double streamTime, RtAudioStreamStatus status, void *userData
-       );
-       int __masterPlay(void *out_buf, void *in_buf, unsigned n_frames);
-
-       /* updateFrameBars
-        * updates bpm, frames, beats and so on. */
-
-       void updateFrameBars();
-
-       /* isSilent
-        * is mixer silent? */
-
-       bool isSilent();
-
-       /* rewind
-        * rewind sequencer to sample 0. */
-
-       void rewind();
-
-       /* updateQuanto
-        * recomputes the quanto between two quantizations */
-
-       void updateQuanto();
-
-       /* hasLogicalSamples
-        * true if 1 or more samples are logical (memory only, such as takes) */
-
-       bool hasLogicalSamples();
-
-       /* hasEditedSamples
-        * true if 1 or more samples was edited via gEditor */
-
-       bool hasEditedSamples();
-
-       /* mergeVirtualInput
-        * memcpy the virtual channel input in the channel designed for input
-        * recording. Called by mixerHandler on stopInputRec() */
-
-       bool mergeVirtualInput();
-
-       /* getChannelByIndex
-        * return channel with given index 'i'. */
-
-       Channel *getChannelByIndex(int i);
-
-       inline Channel* getLastChannel() { return channels.at(channels.size-1); }
-
-
-       /* ---------------------------------------------------------------- */
-
-
-       enum {    // const - what to do when a fadeout ends
-               DO_STOP   = 0x01,
-               DO_MUTE   = 0x02,
-               DO_MUTE_I = 0x04
-       };
-
-       enum {    // const - fade types
-               FADEOUT = 0x01,
-               XFADE   = 0x02
-       };
-
-       gVector<class Channel*> channels;
-
-       bool   running;
-       bool   ready;
-       float *vChanInput;        // virtual channel for recording
-       float *vChanInToOut;      // virtual channel in->out bridge (hear what you're playin)
-       int    frameSize;
-       float  outVol;
-       float  inVol;
-       float  peakOut;
-       float  peakIn;
-       int    quanto;
-       char   quantize;
-       bool     metronome;
-       float  bpm;
-       int    bars;
-       int    beats;
-       int    waitRec;      // delayComp guard
-
-       bool docross;                      // crossfade guard
-       bool rewindWait;           // rewind guard, if quantized
-
-       int framesPerBar;      // frames in one bar
-       int framesPerBeat;     // frames in one beat
-       int framesInSequencer; // frames in the whole sequencer
-       int totalFrames;       // frames in the selected range (e.g. 4/4)
-       int actualFrame;
-       int actualBeat;
-
-#define TICKSIZE 38
-       static float tock[TICKSIZE];
-       static float tick[TICKSIZE];
-       int  tickTracker, tockTracker;
-       bool tickPlay, tockPlay; // 1 = play, 0 = stop
-
-       /* chanInput
-        * the active channel during a recording. NULL = no channels active */
-
-       class SampleChannel *chanInput;
-
-       /* inputTracker
-        * position of the sample in the input side (recording) */
-
-       int inputTracker;
-
-       /* inToOut
-        * copy, process and paste the input into the output, in order to
-        * obtain a "hear what you're playing" feature. */
-
-       bool inToOut;
-
-       pthread_mutex_t mutex_recs;
-       pthread_mutex_t mutex_chans;
-       pthread_mutex_t mutex_plugins;
-
-
-private:
-
-       int midiTCstep;      // part of MTC to send (0 to 7)
-       int midiTCrate;      // send MTC data every midiTCrate frames
-       int midiTCframes;
-       int midiTCseconds;
-       int midiTCminutes;
-       int midiTChours;
-
-       /* getNewIndex
-        * compute new index value for new channels */
-
-       int getNewIndex();
-
-       /* sendMIDIsync
-        * generate MIDI sync output data */
-
-       void sendMIDIsync();
-
-       /* sendMIDIrewind
-        * rewind timecode to beat 0 and also send a MTC full frame to cue
-        * the slave */
-
-       void sendMIDIrewind();
-};
-
-#endif
diff --git a/src/mixerHandler.cpp b/src/mixerHandler.cpp
deleted file mode 100644 (file)
index 4bd520f..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * mixerHandler
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#if defined(__linux__)
-       #include <jack/jack.h>
-       #include <jack/intclient.h>
-       #include <jack/transport.h>
-#endif
-
-#include "mixerHandler.h"
-#include "kernelMidi.h"
-#include "mixer.h"
-#include "const.h"
-#include "utils.h"
-#include "init.h"
-#include "pluginHost.h"
-#include "plugin.h"
-#include "waveFx.h"
-#include "glue.h"
-#include "conf.h"
-#include "patch.h"
-#include "recorder.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "wave.h"
-#include "log.h"
-
-
-extern Mixer             G_Mixer;
-extern Patch             G_Patch;
-extern Conf              G_Conf;
-
-#ifdef WITH_VST
-extern PluginHost G_PluginHost;
-#endif
-
-
-void mh_stopSequencer()
-{
-       G_Mixer.running = false;
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               G_Mixer.channels.at(i)->stopBySeq();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void mh_clear()
-{
-       G_Mixer.running = false;
-       while (G_Mixer.channels.size > 0)
-               G_Mixer.channels.del(0U);  // unsigned
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool mh_uniqueSolo(Channel *ch)
-{
-       int solos = 0;
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               Channel *ch = G_Mixer.channels.at(i);
-               if (ch->solo) solos++;
-               if (solos > 1) return false;
-       }
-       return true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/** TODO - revision needed: mh should not call glue_addChannel */
-
-void mh_loadPatch(bool isProject, const char *projPath)
-{
-       G_Mixer.init();
-       G_Mixer.ready = false;   // put it in wait mode
-
-       int numChans = G_Patch.getNumChans();
-       for (int i=0; i<numChans; i++) {
-
-               Channel *ch = glue_addChannel(G_Patch.getColumn(i), G_Patch.getType(i));
-
-               char smpPath[PATH_MAX];
-
-               /* projects < 0.6.3 version are not portable. Just use the regular
-                * samplePath */
-               /* TODO version >= 0.10.0 - old stuff, remove backward compatibility */
-
-               if (isProject && G_Patch.version >= 0.63f)
-                       sprintf(smpPath, "%s%s%s", gDirname(projPath).c_str(), gGetSlash().c_str(), G_Patch.getSamplePath(i).c_str());
-               else
-                       sprintf(smpPath, "%s", G_Patch.getSamplePath(i).c_str());
-
-               ch->loadByPatch(smpPath, i);
-       }
-
-       G_Mixer.outVol     = G_Patch.getOutVol();
-       G_Mixer.inVol      = G_Patch.getInVol();
-       G_Mixer.bpm        = G_Patch.getBpm();
-       G_Mixer.bars       = G_Patch.getBars();
-       G_Mixer.beats      = G_Patch.getBeats();
-       G_Mixer.quantize   = G_Patch.getQuantize();
-       G_Mixer.metronome  = G_Patch.getMetronome();
-       G_Patch.lastTakeId = G_Patch.getLastTakeId();
-       G_Patch.samplerate = G_Patch.getSamplerate();
-
-       /* rewind and update frames in Mixer (it's vital) */
-
-       G_Mixer.rewind();
-       G_Mixer.updateFrameBars();
-       G_Mixer.ready = true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void mh_rewindSequencer()
-{
-       if (G_Mixer.quantize > 0 && G_Mixer.running)   // quantize rewind
-               G_Mixer.rewindWait = true;
-       else
-               G_Mixer.rewind();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-SampleChannel *mh_startInputRec()
-{
-       /* search for the next available channel */
-
-       SampleChannel *chan = NULL;
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
-                       if (((SampleChannel*) G_Mixer.channels.at(i))->canInputRec()) {
-                       chan = (SampleChannel*) G_Mixer.channels.at(i);
-                       break;
-               }
-       }
-
-       /* no chans available? */
-
-       if (chan == NULL)
-               return NULL;
-
-       Wave *w = new Wave();
-       if (!w->allocEmpty(G_Mixer.totalFrames))
-               return NULL;
-
-       /* increase lastTakeId until the sample name TAKE-[n] is unique */
-
-       char name[32];
-       sprintf(name, "TAKE-%d", G_Patch.lastTakeId);
-       while (!mh_uniqueSamplename(chan, name)) {
-               G_Patch.lastTakeId++;
-               sprintf(name, "TAKE-%d", G_Patch.lastTakeId);
-       }
-
-       chan->allocEmpty(G_Mixer.totalFrames, G_Patch.lastTakeId);
-       G_Mixer.chanInput = chan;
-
-       /* start to write from the actualFrame, not the beginning */
-       /** FIXME: move this before wave allocation*/
-
-       G_Mixer.inputTracker = G_Mixer.actualFrame;
-
-       gLog(
-               "[mh] start input recs using chan %d with size %d, frame=%d\n",
-               chan->index, G_Mixer.totalFrames, G_Mixer.inputTracker
-       );
-
-       return chan;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-SampleChannel *mh_stopInputRec()
-{
-       gLog("[mh] stop input recs\n");
-       G_Mixer.mergeVirtualInput();
-       SampleChannel *ch = G_Mixer.chanInput;
-       G_Mixer.chanInput = NULL;
-       G_Mixer.waitRec   = 0;                                  // if delay compensation is in use
-       return ch;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool mh_uniqueSamplename(SampleChannel *ch, const char *name)
-{
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               if (ch != G_Mixer.channels.at(i)) {
-                       if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
-                               SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i);
-                               if (other->wave != NULL)
-                                       if (!strcmp(name, other->wave->name.c_str()))
-                                               return false;
-                       }
-               }
-       }
-       return true;
-}
diff --git a/src/mixerHandler.h b/src/mixerHandler.h
deleted file mode 100644 (file)
index f842004..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * mixerHandler
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef MIXERHANDLER_H
-#define MIXERHANDLER_H
-
-
-#include "recorder.h"
-
-
-/* stopSequencer
- * stop the sequencer, with special case if samplesStopOnSeqHalt is
- * true. */
-
-void mh_stopSequencer();
-
-void mh_rewindSequencer();
-
-/* clear
- * stop everything and clear all channels. */
-void mh_clear();
-
-/* uniqueSolo
- * true if ch is the only solo'd channel in mixer. */
-
-bool mh_uniqueSolo(class Channel *ch);
-
-/* loadPatch
- * load a path or a project (if isProject) into Mixer. If isProject, path
- * must contain the address of the project folder. */
-
-void mh_loadPatch(bool isProject, const char *projPath=0);
-
-/* startInputRec - record from line in
- * creates a new empty wave in the first available channels and returns
- * the chan number chosen, otherwise -1 if there are no more empty
- * channels available. */
-
-SampleChannel *mh_startInputRec();
-
-SampleChannel *mh_stopInputRec();
-
-/* uniqueSamplename
- * return true if samplename 'n' is unique. Requires SampleChannel *ch
- * in order to skip check against itself. */
-
-bool mh_uniqueSamplename(class SampleChannel *ch, const char *name);
-
-#endif
diff --git a/src/patch.cpp b/src/patch.cpp
deleted file mode 100644 (file)
index 005c691..0000000
+++ /dev/null
@@ -1,744 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * patch
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdint.h>
-#include "patch.h"
-#include "init.h"
-#include "recorder.h"
-#include "utils.h"
-#include "conf.h"
-#include "pluginHost.h"
-#include "wave.h"
-#include "mixer.h"
-#include "channel.h"
-#include "log.h"
-#include "gd_mainWindow.h"
-#include "gg_keyboard.h"
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-#ifdef WITH_VST
-extern PluginHost    G_PluginHost;
-#endif
-extern gdMainWindow *mainWin;
-
-
-int Patch::open(const char *file)
-{
-       fp = fopen(file, "r");
-       if (fp == NULL)
-               return PATCH_UNREADABLE;
-
-       if (getValue("header") != "GIADAPTC")
-               return PATCH_INVALID;
-
-       version = atof(getValue("versionf").c_str());
-       gLog("[PATCH] open patch version %f\n", version);
-       if (version == 0.0)
-               gLog("[PATCH] patch < 0.6.1, backward compatibility mode\n");
-
-       return PATCH_OPEN_OK;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Patch::setDefault()
-{
-       name[0]    = '\0';
-  lastTakeId = 0;
-  samplerate = DEFAULT_SAMPLERATE;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::close()
-{
-       return fclose(fp);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Patch::getName()
-{
-       std::string out = getValue("patchname");
-       strncpy(name, out.c_str(), MAX_PATCHNAME_LEN);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string Patch::getSamplePath(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "samplepath%d", c);
-       return getValue(tmp);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getPitch(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanPitch%d", c);
-       float out = atof(getValue(tmp).c_str());
-       if (out > 2.0f || out < 0.1f)
-               return 1.0f;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getNumChans()
-{
-       if (version == 0.0)      // backward compatibility with version < 0.6.1
-               return 32;
-       return atoi(getValue("channels").c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getNumColumns()
-{
-       return atoi(getValue("columns").c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getColumn(int c)
-{
-       if (version == 0.0)      // backward compatibility with version < 0.6.1
-               return 0;
-       char tmp[16];
-       sprintf(tmp, "chanColumn%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getIndex(int c)
-{
-       if (version == 0.0)      // backward compatibility with version < 0.6.1
-               return c;
-
-       char tmp[16];
-       sprintf(tmp, "chanIndex%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getVol(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanvol%d", c);
-       float out = atof(getValue(tmp).c_str());
-       if (out > 1.0f || out < 0.0f)
-               return DEFAULT_VOL;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getMode(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanmode%d", c);
-       int out = atoi(getValue(tmp).c_str());
-       if (out & (LOOP_ANY | SINGLE_ANY))
-               return out;
-       return DEFAULT_CHANMODE;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getMute(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanMute%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getMute_s(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanMute_s%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getSolo(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanSolo%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getType(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanType%d", c);
-       int out = atoi(getValue(tmp).c_str());
-       if (out == 0)
-               return CHANNEL_SAMPLE;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getBegin(int c)
-{
-       char tmp[16];
-       if (version < 0.73f)
-               sprintf(tmp, "chanstart%d", c);
-       else
-               sprintf(tmp, "chanBegin%d", c);
-       int out = atoi(getValue(tmp).c_str());
-       if (out < 0)
-               return 0;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getEnd(int c, unsigned size)
-{
-       char tmp[16];
-       sprintf(tmp, "chanend%d", c);
-
-       /* if chanEnd doesn't exist, it returns an atoi(empty string) == 0.
-        * good in theory, a disaster in practice. */
-
-       std::string val = getValue(tmp);
-       if (val == "")
-               return size;
-
-       unsigned out = atoi(val.c_str());
-       if (out <= 0 || out > size)
-               return size;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getBoost(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanBoost%d", c);
-       float out = atof(getValue(tmp).c_str());
-       if (out < 1.0f)
-               return DEFAULT_BOOST;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getPanLeft(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanPanLeft%d", c);
-       std::string val = getValue(tmp);
-       if (val == "")
-               return 1.0f;
-
-       float out = atof(val.c_str());
-       if (out < 0.0f || out > 1.0f)
-               return 1.0f;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getKey(int c)
-{
-       if (version == 0.0)      // backward compatibility with version < 0.6.1
-               return 0;
-       char tmp[16];
-       sprintf(tmp, "chanKey%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getPanRight(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanPanRight%d", c);
-       std::string val = getValue(tmp);
-       if (val == "")
-               return 1.0f;
-
-       float out = atof(val.c_str());
-       if (out < 0.0f || out > 1.0f)
-               return 1.0f;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool Patch::getRecActive(int c)
-{
-       char tmp[16];
-       sprintf(tmp, "chanRecActive%d", c);
-       return atoi(getValue(tmp).c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getOutVol()
-{
-       return atof(getValue("outVol").c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getInVol()
-{
-       return atof(getValue("inVol").c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float Patch::getBpm()
-{
-       float out = atof(getValue("bpm").c_str());
-       if (out < 20.0f || out > 999.0f)
-               return DEFAULT_BPM;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getBars()
-{
-       int out = atoi(getValue("bars").c_str());
-       if (out <= 0 || out > 32)
-               return DEFAULT_BARS;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getBeats()
-{
-       int out = atoi(getValue("beats").c_str());
-       if (out <= 0 || out > 32)
-               return DEFAULT_BEATS;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getQuantize()
-{
-       int out = atoi(getValue("quantize").c_str());
-       if (out < 0 || out > 8)
-               return DEFAULT_QUANTIZE;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool Patch::getMetronome()
-{
-       bool out = atoi(getValue("metronome").c_str());
-       if (out != true || out != false)
-               return false;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getLastTakeId()
-{
-       return atoi(getValue("lastTakeId").c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::getSamplerate()
-{
-       int out = atoi(getValue("samplerate").c_str());
-       if (out <= 0)
-               return DEFAULT_SAMPLERATE;
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-uint32_t Patch::getMidiValue(int i, const char *c)
-{
-       char tmp[32];
-       sprintf(tmp, "chanMidi%s%d", c, i);
-       return strtoul(getValue(tmp).c_str(), NULL, 10);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::readRecs()
-{
-       gLog("[PATCH] Reading recs...\n");
-
-       unsigned numrecs = atoi(getValue("numrecs").c_str());
-
-       for (unsigned i=0; i<numrecs; i++) {
-               int frame, recPerFrame;
-
-               /* parsing 'dddddd d': [framenumber] [num. recs for that frame]  */
-
-               char tmpbuf[16];
-               sprintf(tmpbuf, "recframe%d", i);
-               sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame);
-
-//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
-
-               for (int k=0; k<recPerFrame; k++) {
-                       int      chan = 0;
-                       int      type = 0;
-                       float    fValue = 0.0f;
-                       int      iValue_fix = 0;
-                       uint32_t iValue = 0;
-
-                       /* reading info for each frame: %d|%d */
-
-                       char tmpbuf[16];
-                       sprintf(tmpbuf, "f%da%d", i, k);
-
-                       if (version < 0.61f)    // no float and int values
-                               sscanf(getValue(tmpbuf).c_str(), "%d|%d", &chan, &type);
-                       else
-                               if (version < 0.83f)  // iValues were stored as signed int (wrong)
-                                       sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%d", &chan, &type, &fValue, &iValue_fix);
-                               else
-                                       sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%u", &chan, &type, &fValue, &iValue);
-
-//gLog("  loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
-
-                       Channel *ch = G_Mixer.getChannelByIndex(chan);
-                       if (ch)
-                               if (ch->status & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) {
-                                       if (version < 0.83f)
-                                               recorder::rec(ch->index, type, frame, iValue_fix, fValue);
-                                       else
-                                               recorder::rec(ch->index, type, frame, iValue, fValue);
-                               }
-               }
-       }
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-int Patch::readPlugins()
-{
-       gLog("[PATCH] Reading plugins...\n");
-
-       int globalOut = 1;
-
-       /* master plugins */
-
-       globalOut &= readMasterPlugins(PluginHost::MASTER_IN);
-       globalOut &= readMasterPlugins(PluginHost::MASTER_OUT);
-
-       /* channel plugins */
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               Channel *ch = G_Mixer.channels.at(i);
-
-               char tmp[MAX_LINE_LEN];
-               sprintf(tmp, "chan%dPlugins", ch->index);
-               int np = atoi(getValue(tmp).c_str());
-
-               for (int j=0; j<np; j++) {
-                       sprintf(tmp, "chan%d_p%dpathfile", ch->index, j);
-                       int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), PluginHost::CHANNEL, ch);
-                       if (out != 0) {
-                               sprintf(tmp, "chan%d_p%dnumParams", ch->index, j);
-                               int nparam = atoi(getValue(tmp).c_str());
-                               Plugin *pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch);
-                               sprintf(tmp, "chan%d_p%dbypass", ch->index, j);
-                               pPlugin->bypass = atoi(getValue(tmp).c_str());
-                               for (int k=0; k<nparam; k++) {
-                                       sprintf(tmp, "chan%d_p%dparam%dvalue", ch->index, j, k);
-                                       float pval = atof(getValue(tmp).c_str());
-                                       pPlugin->setParam(k, pval);
-                               }
-                       }
-                       globalOut &= out;
-               }
-       }
-       return globalOut;
-}
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::write(const char *file, const char *name, bool project)
-{
-       fp = fopen(file, "w");
-       if (fp == NULL)
-               return 0;
-
-       fprintf(fp, "# --- Giada patch file --- \n");
-       fprintf(fp, "header=GIADAPTC\n");
-       fprintf(fp, "version=%s\n",    VERSIONE);
-       fprintf(fp, "versionf=%f\n",   VERSIONE_FLOAT);
-       fprintf(fp, "patchname=%s\n",  name);
-       fprintf(fp, "bpm=%f\n",        G_Mixer.bpm);
-       fprintf(fp, "bars=%d\n",       G_Mixer.bars);
-       fprintf(fp, "beats=%d\n",      G_Mixer.beats);
-       fprintf(fp, "quantize=%d\n",   G_Mixer.quantize);
-       fprintf(fp, "outVol=%f\n",     G_Mixer.outVol);
-       fprintf(fp, "inVol=%f\n",      G_Mixer.inVol);
-       fprintf(fp, "metronome=%d\n",  G_Mixer.metronome);
-       fprintf(fp, "lastTakeId=%d\n", lastTakeId);
-       fprintf(fp, "samplerate=%d\n", G_Conf.samplerate);      // original samplerate when the patch was saved
-       fprintf(fp, "channels=%d\n",   G_Mixer.channels.size);
-       fprintf(fp, "columns=%d\n",    mainWin->keyboard->getTotalColumns());
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               fprintf(fp, "# --- channel %d --- \n", i);
-               G_Mixer.channels.at(i)->writePatch(fp, i, project);
-       }
-
-       /* writing recs. Warning: channel index is not mixer.channels.at(chan),
-        * but mixer.channels.at(chan)->index! */
-
-       fprintf(fp, "# --- actions --- \n");
-       fprintf(fp, "numrecs=%d\n", recorder::global.size);
-       for (unsigned i=0; i<recorder::global.size; i++) {
-               fprintf(fp, "recframe%d=%d %d\n", i, recorder::frames.at(i), recorder::global.at(i).size);
-               for (unsigned k=0; k<recorder::global.at(i).size; k++) {
-                       fprintf(fp, "f%da%d=%d|%d|%f|%u\n",
-                               i, k,
-                               recorder::global.at(i).at(k)->chan,
-                               recorder::global.at(i).at(k)->type,
-                               recorder::global.at(i).at(k)->fValue,
-                               recorder::global.at(i).at(k)->iValue);
-               }
-       }
-
-#ifdef WITH_VST
-
-       /* writing master VST parameters */
-
-       writeMasterPlugins(PluginHost::MASTER_IN);
-       writeMasterPlugins(PluginHost::MASTER_OUT);
-
-       /* writing VST parameters, channels. chan%d is mixer::channels.at(%d)->index,
-        * not mixer::chanels.at(%d)! */
-
-       int numPlugs;
-       int numParams;
-       Plugin *pPlugin;
-
-       fprintf(fp, "# --- VST / channels --- \n");
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               Channel *ch = G_Mixer.channels.at(i);
-               numPlugs    = G_PluginHost.countPlugins(PluginHost::CHANNEL, ch);
-               fprintf(fp, "chan%dPlugins=%d\n", ch->index, numPlugs);
-
-               for (int j=0; j<numPlugs; j++) {
-                       pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch);
-                       if (!pPlugin->status) {
-                               gLog("[PATCH] Plugin %d is in a bad status, skip writing params\n", i);
-                               continue;
-                       }
-                       fprintf(fp, "chan%d_p%dpathfile=%s\n", ch->index, j, pPlugin->pathfile);
-                       fprintf(fp, "chan%d_p%dbypass=%d\n",   ch->index, j, pPlugin->bypass);
-                       numParams = pPlugin->getNumParams();
-                       fprintf(fp, "chan%d_p%dnumParams=%d\n", ch->index, j, numParams);
-
-                       for (int k=0; k<numParams; k++)
-                               fprintf(fp, "chan%d_p%dparam%dvalue=%f\n", ch->index, j, k, pPlugin->getParam(k));
-               }
-       }
-
-#endif
-
-       fclose(fp);
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef WITH_VST
-
-int Patch::readMasterPlugins(int type)
-{
-       int  nmp;
-       char chr;
-       int  res = 1;
-
-       if (type == PluginHost::MASTER_IN) {
-               chr = 'I';
-               nmp = atoi(getValue("masterIPlugins").c_str());
-       }
-       else {
-               chr = 'O';
-               nmp = atoi(getValue("masterOPlugins").c_str());
-       }
-
-       for (int i=0; i<nmp; i++) {
-               char tmp[MAX_LINE_LEN];
-               sprintf(tmp, "master%c_p%dpathfile", chr, i);
-               int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), type);
-               if (out != 0) {
-                       Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
-                       sprintf(tmp, "master%c_p%dbypass", chr, i);
-                       pPlugin->bypass = atoi(getValue(tmp).c_str());
-                       sprintf(tmp, "master%c_p%dnumParams", chr, i);
-                       int nparam = atoi(getValue(tmp).c_str());
-                       for (int j=0; j<nparam; j++) {
-                               sprintf(tmp, "master%c_p%dparam%dvalue", chr, i, j);
-                               float pval = atof(getValue(tmp).c_str());
-                               pPlugin->setParam(j, pval);
-                       }
-               }
-               res &= out;
-       }
-
-       return res;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Patch::writeMasterPlugins(int type)
-{
-       char chr;
-
-       if (type == PluginHost::MASTER_IN) {
-               fprintf(fp, "# --- VST / master in --- \n");
-               chr = 'I';
-       }
-       else {
-               fprintf(fp, "# --- VST / master out --- \n");
-               chr = 'O';
-       }
-
-       int nmp = G_PluginHost.countPlugins(type);
-       fprintf(fp, "master%cPlugins=%d\n", chr, nmp);
-
-       for (int i=0; i<nmp; i++) {
-
-               Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
-               if (!pPlugin->status) {
-                       gLog("[PATCH] Plugin %d is in a bad status, skip writing params\n", i);
-                       continue;
-               }
-
-               fprintf(fp, "master%c_p%dpathfile=%s\n", chr, i, pPlugin->pathfile);
-               fprintf(fp, "master%c_p%dbypass=%d\n", chr, i, pPlugin->bypass);
-               int numParams = pPlugin->getNumParams();
-               fprintf(fp, "master%c_p%dnumParams=%d\n", chr, i, numParams);
-
-               for (int j=0; j<numParams; j++)
-                       fprintf(fp, "master%c_p%dparam%dvalue=%f\n", chr, i, j, pPlugin->getParam(j));
-       }
-}
-
-#endif
diff --git a/src/patch.h b/src/patch.h
deleted file mode 100644 (file)
index e431b85..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * patch
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef __PATCH_H__
-#define __PATCH_H__
-
-#include <stdio.h>
-#include <string>
-#include <stdint.h>
-#include "dataStorage.h"
-#include "const.h"
-
-
-class Patch : public DataStorage {
-
-private:
-       int  readMasterPlugins(int type);
-       void writeMasterPlugins(int type);
-
-public:
-
-       char  name[MAX_PATCHNAME_LEN];
-       float version;
-       int   lastTakeId;
-       int   samplerate;
-
-       int         open(const char *file);
-       void        setDefault();
-       int         close();
-
-       void                            getName       ();
-       int         getNumChans   ();
-       int                                     getNumColumns ();
-       std::string getSamplePath (int i);
-       float       getVol        (int i);
-       int         getMode       (int i);
-       int         getMute       (int i);
-       int         getMute_s     (int i);
-       int         getSolo       (int i);
-       int         getBegin      (int i);
-       int         getEnd        (int i, unsigned sampleSize);
-       float       getBoost      (int i);
-       float       getPanLeft    (int i);
-       float       getPanRight   (int i);
-       float       getPitch      (int i);
-       bool        getRecActive  (int i);
-       int         getColumn     (int i);
-       int         getIndex      (int i);
-       int         getType       (int i);
-       int         getKey        (int i);
-       uint32_t    getMidiValue  (int i, const char *c);
-       float       getOutVol     ();
-       float       getInVol      ();
-       float       getBpm        ();
-       int         getBars       ();
-       int         getBeats      ();
-       int         getQuantize   ();
-       bool        getMetronome  ();
-       int         getLastTakeId ();
-       int         getSamplerate ();
-
-       int         write(const char *file, const char *name, bool isProject);
-       int         readRecs();
-#ifdef WITH_VST
-       int         readPlugins();
-#endif
-};
-
-#endif
diff --git a/src/plugin.cpp b/src/plugin.cpp
deleted file mode 100644 (file)
index 17cace3..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-
-
-#include "plugin.h"
-#include "log.h"
-
-
-int Plugin::id_generator = 0;
-
-
-/* ------------------------------------------------------------------ */
-
-
-Plugin::Plugin()
-       : module    (NULL),
-         entryPoint(NULL),
-         plugin    (NULL),
-         id        (id_generator++),
-         program   (-1),
-         bypass    (false),
-         suspended (false)
-{}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Plugin::~Plugin() {
-       unload();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::unload() {
-
-       if (module == NULL)
-               return 1;
-
-#if defined(_WIN32)
-
-       FreeLibrary((HMODULE)module); // FIXME - error checking
-       return 1;
-
-#elif defined(__linux__)
-
-       return dlclose(module) == 0 ? 1 : 0;
-
-#elif defined(__APPLE__)
-
-       /* we must unload bundles but because bundles may be in use for other
-       plug-in types it is important (and mandatory on certain plug-ins,
-       e.g. Korg) to do a check on the retain count. */
-
-       CFIndex retainCount = CFGetRetainCount(module);
-
-       if (retainCount == 1) {
-               gLog("[plugin] retainCount == 1, can unload dlyb\n");
-               CFBundleUnloadExecutable(module);
-               CFRelease(module);
-       }
-       else
-               gLog("[plugin] retainCount > 1 (%d), leave dlyb alone\n", (int) retainCount);
-
-       return 1;
-
-#endif
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::load(const char *fname) {
-
-       strcpy(pathfile, fname);
-
-#if defined(_WIN32)
-
-       module = LoadLibrary(pathfile);
-
-#elif defined(__linux__)
-
-       module = dlopen(pathfile, RTLD_LAZY);
-
-#elif defined(__APPLE__)
-
-  /* creates the path to the bundle. In OSX vsts are stored inside the
-   * so-called bundles, just a directory with '.vst' extension. Finally
-   * we open the bundle with CFBundleCreate. */
-
-  CFStringRef pathStr   = CFStringCreateWithCString(NULL, pathfile, kCFStringEncodingASCII);
-  CFURLRef    bundleUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,   pathStr, kCFURLPOSIXPathStyle, true);
-  if(bundleUrl == NULL) {
-    gLog("[plugin] unable to create URL reference for plugin\n");
-    status = 0;
-    return 0;
-  }
-  module = CFBundleCreate(kCFAllocatorDefault, bundleUrl);
-
-#endif
-
-       if (module) {
-
-       /* release (free) any old string */
-
-#ifdef __APPLE__
-               CFRelease(pathStr);
-               CFRelease(bundleUrl);
-#endif
-               //strcpy(pathfile, fname); ???????????
-               status = 1;
-               return 1;
-       }
-       else {
-
-#if defined(_WIN32)
-
-               gLog("[plugin] unable to load %s, error: %d\n", fname, (int) GetLastError());
-
-#elif defined(__linux__)
-
-               gLog("[plugin] unable to load %s, error: %s\n", fname, dlerror());
-
-#elif defined(__APPLE__)
-
-    gLog("[plugin] unable to create bundle reference\n");
-    CFRelease(pathStr);
-    CFRelease(bundleUrl);
-
-#endif
-               status = 0;
-               return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::init(VstIntPtr VSTCALLBACK (*HostCallback) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt)) {
-
-#if defined(_WIN32)
-
-       entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "VSTPluginMain");
-       if (!entryPoint)
-               entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "main");
-
-#elif defined(__linux__)
-
-       /* bad stuff here: main() is a function pointer, dlsym(module, "main")
-        * returns a pointer to an object (void*) which should be casted to
-        * a pointer to function (main(), precisely). Unfortunately the standard
-        * forbids the conversion from void* to function pointer. So we do a raw
-        * mem copy from tmp to entryPoint. */
-
-       void *tmp;
-       tmp = dlsym(module, "VSTPluginMain");
-       if (!tmp)
-               tmp = dlsym(module, "main");
-       memcpy(&entryPoint, &tmp, sizeof(tmp));
-
-#elif defined(__APPLE__)
-
-       /* same also for Unix/OSX. */
-
-       void *tmp = NULL;
-       tmp = CFBundleGetFunctionPointerForName(module, CFSTR("VSTPluginMain"));
-
-       if (!tmp) {
-               gLog("[plugin] entryPoint 'VSTPluginMain' not found\n");
-               tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main_macho"));  // VST SDK < 2.4
-       }
-       if (!tmp) {
-               gLog("[plugin] entryPoint 'main_macho' not found\n");
-               tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main"));
-       }
-       if (tmp)
-               memcpy(&entryPoint, &tmp, sizeof(tmp));
-       else
-               gLog("[plugin] entryPoint 'main' not found\n");
-
-#endif
-
-       /* if entry point is found, add to plugin a pointer to hostCallback. Or
-        * in other words bind the callback to the plugin. */
-
-       if (entryPoint) {
-               gLog("[plugin] entryPoint found\n");
-               plugin = entryPoint(HostCallback);
-               if (!plugin) {
-                       gLog("[plugin] failed to create effect instance!\n");
-                       return 0;
-               }
-       }
-       else {
-               gLog("[plugin] entryPoint not found, unable to proceed\n");
-               return 0;
-       }
-
-
-       /* check the magicNumber */
-       /** WARNING: on Windows one can load any DLL! Why!?! */
-
-  if(plugin->magic == kEffectMagic) {
-               gLog("[plugin] magic number OK\n");
-               return 1;
-       }
-       else {
-    gLog("[plugin] magic number is bad\n");
-    return 0;
-  }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::setup(int samplerate, int frames) {
-
-  /* init plugin through the dispatcher with some basic infos */
-
-  plugin->dispatcher(plugin, effOpen, 0, 0, 0, 0);
-       plugin->dispatcher(plugin, effSetSampleRate, 0, 0, 0, samplerate);
-       plugin->dispatcher(plugin, effSetBlockSize, 0, frames, 0, 0);
-
-       /* check SDK compatibility */
-
-       if (getSDKVersion() != kVstVersion)
-               gLog("[plugin] warning: different VST version (host: %d, plugin: %d)\n", kVstVersion, getSDKVersion());
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-AEffect *Plugin::getPlugin() {
-       return plugin;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getId() { return id; }
-
-
-/* ------------------------------------------------------------------ */
-
-int Plugin::getSDKVersion() {
-       return plugin->dispatcher(plugin, effGetVstVersion, 0, 0, 0, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getName(char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetEffectName, 0, 0, tmp, 0);
-       tmp[kVstMaxEffectNameLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxEffectNameLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getVendor(char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetVendorString, 0, 0, tmp, 0);
-       tmp[kVstMaxVendorStrLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxVendorStrLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getProduct(char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetProductString, 0, 0, tmp, 0);
-       tmp[kVstMaxProductStrLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxProductStrLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getNumPrograms() { return plugin->numPrograms; }
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::setProgram(int index) {
-       plugin->dispatcher(plugin, effBeginSetProgram, 0, 0, 0, 0);
-       plugin->dispatcher(plugin, effSetProgram, 0, index, 0, 0);
-       gLog("[plugin] program changed, index %d\n", index);
-       program = index;
-       return plugin->dispatcher(plugin, effEndSetProgram, 0, 0, 0, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getNumParams() { return plugin->numParams; }
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getNumInputs() { return plugin->numInputs; }
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getNumOutputs() {  return plugin->numOutputs; }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getProgramName(int index, char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetProgramNameIndexed, index, 0, tmp, 0);
-       tmp[kVstMaxProgNameLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxProgNameLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getParamName(int index, char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetParamName, index, 0, tmp, 0);
-       tmp[kVstMaxParamStrLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxParamStrLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getParamLabel(int index, char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetParamLabel, index, 0, tmp, 0);
-       tmp[kVstMaxParamStrLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxParamStrLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getParamDisplay(int index, char *out) {
-       char tmp[128] = "\0";
-       plugin->dispatcher(plugin, effGetParamDisplay, index, 0, tmp, 0);
-       tmp[kVstMaxParamStrLen-1] = '\0';
-       strncpy(out, tmp, kVstMaxParamStrLen);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-float Plugin::getParam(int index) {
-       return plugin->getParameter(plugin, index);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::setParam(int index, float value) {
-       plugin->setParameter(plugin, index, value);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool Plugin::hasGui() {
-       return plugin->flags & effFlagsHasEditor;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::openGui(void *w) {
-       long val = 0;
-#ifdef __linux__
-  val = (long) w;
-#endif
-       plugin->dispatcher(plugin, effEditOpen, 0, val, w, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::closeGui() {
-       plugin->dispatcher(plugin, effEditClose, 0, 0, 0, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getGuiWidth() {
-       ERect *pErect = NULL;
-       plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0);
-       return pErect->top + pErect->right;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Plugin::getGuiHeight() {
-       ERect *pErect = NULL;
-       plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0);
-       return pErect->top + pErect->bottom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::idle() {
-       plugin->dispatcher(plugin, effEditIdle, 0, 0, NULL, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::processAudio(float **in, float **out, long frames) {
-       plugin->processReplacing(plugin, in, out, frames);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::processEvents(VstEvents *events) {
-       plugin->dispatcher(plugin, effProcessEvents, 0, 0, events, 0.0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::resume() {
-       plugin->dispatcher(plugin, effMainsChanged, 0, 1, 0, 0);
-       suspended = false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::suspend() {
-       plugin->dispatcher(plugin, effMainsChanged, 0, 0, 0, 0);
-       suspended = true;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::close() {
-       plugin->dispatcher(plugin, effClose, 0, 0, 0, 0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Plugin::getRect(ERect **out) {
-       plugin->dispatcher(plugin, effEditGetRect, 0, 0, out, 0);
-}
-
-
-#endif
diff --git a/src/plugin.h b/src/plugin.h
deleted file mode 100644 (file)
index 0dbaef7..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * plugin
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifdef WITH_VST
-
-#ifndef __PLUGIN_H
-#define __PLUGIN_H
-
-#include <cstdio>
-
-/* before including aeffetx(x).h we must define __cdecl, otherwise VST
- * headers can't be compiled correctly. In windows __cdecl is already
- * defined. */
-
-#ifdef __GNUC__
-       #ifndef _WIN32
-               #define __cdecl
-       #endif
-#endif
-
-#include "vst/aeffectx.h"
-
-#if defined(_WIN32)
-       #include <windows.h>
-#elif defined(__linux__)
-       #include <dlfcn.h>
-       #include <X11/Xlib.h>
-#elif defined(__APPLE__)
-       #include <CoreFoundation/CFBundle.h>
-#endif
-
-#include <limits.h>  // PATH_MAX
-
-
-// Plugin's entry point
-typedef AEffect* (*vstPluginFuncPtr)(audioMasterCallback host);
-
-
-class Plugin {
-
-private:
-
-#if defined(_WIN32) || defined(__linux__)
-       void             *module;     // dll, so, ...
-#elif defined(__APPLE__)
-       CFBundleRef       module;                       // OSX bundle
-#endif
-
-       vstPluginFuncPtr  entryPoint; // VST entry point
-       AEffect          *plugin;     // real plugin
-
-       /* each plugin has an unique ID */
-
-       static int id_generator;
-       int        id;
-
-       /* program
-        * selected program. -1 if no program available */
-
-       int program;
-
-       /* unload
-        * free plugin from memory. Calls dlclose and similars. */
-
-       int unload();
-
-public:
-       Plugin();
-       ~Plugin();
-
-       int  load(const char *fname);
-       int  init(VstIntPtr VSTCALLBACK (*HostCallback)(AEffect*, VstInt32, VstInt32, VstIntPtr, void*, float));
-       int  setup(int samplerate, int frames);
-
-       AEffect *getPlugin();
-
-       /* get[Item].
-        * Wrappers called by host when it wants info from the plugin. */
-
-       int   getId();
-       int   getSDKVersion();
-       void  getName   (char *out);
-       void  getVendor (char *out);
-       void  getProduct(char *out);
-       int   getNumPrograms();        // list all programs
-       int   setProgram(int index);   // load a program
-       int   getNumParams();
-       int   getNumInputs();
-       int   getNumOutputs();
-       void  getProgramName(int index, char *out);  // program = preset
-       void  getParamName(int index, char *out);
-       void  getParamLabel(int index, char *out);   // parameter's value(0, -39, ...)
-       void  getParamDisplay(int index, char *out); // parameter's unit measurement (dB, Pan, ...)
-       float getParam(int index);
-       void  getRect(ERect **out);
-       void  setParam(int index, float value);
-
-       bool  hasGui();
-       void  openGui(void *w);
-       void  closeGui();
-       int   getGuiWidth();
-       int   getGuiHeight();
-       void  idle();
-
-       void  processAudio (float **in, float **out, long frames);
-       void  processEvents(VstEvents *events);
-       void  resume();
-       void  suspend();
-       void  close();
-
-       inline int getProgram() { return program; }
-
-       /* there's a specific opcode for the bypass, but we don't trust the
-        * plugin's developers. */
-
-       bool bypass;
-
-       /* the status of the plugin:
-        * 1: ok
-        * 0: missing (file not found) */
-
-       int status;
-
-       /* suspended
-        * true after suspend(), false after resume(). A suspended plugin isn't
-        * processed by pluginHost. */
-
-       bool suspended;
-
-       /* pathfile
-        * full filename path */
-
-       char pathfile[PATH_MAX];
-
-       /* window
-        * plugin must know its window in case of a resize via opcode */
-
-       class gWindow *window;
-};
-
-#endif
-
-#endif // #ifdef WITH_VST
diff --git a/src/pluginHost.cpp b/src/pluginHost.cpp
deleted file mode 100644 (file)
index f28f5aa..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * pluginHost
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifdef WITH_VST
-
-
-#include "pluginHost.h"
-#include "conf.h"
-#include "const.h"
-#include "mixer.h"
-#include "gd_mainWindow.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "kernelMidi.h"
-#include "log.h"
-
-
-extern Conf          G_Conf;
-extern Mixer         G_Mixer;
-extern PluginHost    G_PluginHost;
-extern unsigned      G_beats;
-extern gdMainWindow *mainWin;
-
-
-PluginHost::PluginHost() {
-
-       /* initially we fill vstTimeInfo with trash. Only when the plugin requests
-        * the opcode we load the right infos from G_Mixer. */
-
-       vstTimeInfo.samplePos          = 0.0;
-       vstTimeInfo.sampleRate         = G_Conf.samplerate;
-       vstTimeInfo.nanoSeconds        = 0.0;
-       vstTimeInfo.ppqPos             = 0.0;
-       vstTimeInfo.tempo              = 120.0;
-       vstTimeInfo.barStartPos        = 0.0;
-       vstTimeInfo.cycleStartPos      = 0.0;
-       vstTimeInfo.cycleEndPos        = 0.0;
-       vstTimeInfo.timeSigNumerator   = 4;
-       vstTimeInfo.timeSigDenominator = 4;
-       vstTimeInfo.smpteOffset        = 0;
-       vstTimeInfo.smpteFrameRate     = 1;
-       vstTimeInfo.samplesToNextClock = 0;
-       vstTimeInfo.flags              = 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-PluginHost::~PluginHost() {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int PluginHost::allocBuffers() {
-
-       /** FIXME - ERROR CHECKING! */
-
-       /* never, ever use G_Conf.buffersize to alloc these chunks of memory.
-        * If you use JACK, that value would be meaningless. Always refer to
-        * kernelAudio::realBufsize. */
-
-       int bufSize = kernelAudio::realBufsize*sizeof(float);
-
-       bufferI    = (float **) malloc(2 * sizeof(float*));
-       bufferI[0] =  (float *) malloc(bufSize);
-       bufferI[1] =  (float *) malloc(bufSize);
-
-       bufferO    = (float **) malloc(2 * sizeof(float*));
-       bufferO[0] =  (float *) malloc(bufSize);
-       bufferO[1] =  (float *) malloc(bufSize);
-
-       memset(bufferI[0], 0, bufSize);
-       memset(bufferI[1], 0, bufSize);
-       memset(bufferO[0], 0, bufSize);
-       memset(bufferO[1], 0, bufSize);
-
-       gLog("[pluginHost] buffers allocated, buffersize = %d\n", 2*kernelAudio::realBufsize);
-
-       //printOpcodes();
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-VstIntPtr VSTCALLBACK PluginHost::HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) {
-       return G_PluginHost.gHostCallback(effect, opcode, index, value, ptr, opt);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) {
-
-       /* warning: VST headers compiled with DECLARE_VST_DEPRECATED. */
-
-       switch (opcode) {
-
-               /* 0 - Called after a control has changed in the editor and when
-                * the associated parameter should be automated. Index contains the
-                * param, opt the value. Thanks, but we don't need it now. It will
-                * be useful when recording actions from VST (in the future). */
-
-               case audioMasterAutomate:
-                       return 0;
-
-               /* 1 - host version (2.4) */
-
-               case audioMasterVersion:
-                       return kVstVersion;
-
-               /* 3 - Give idle time to Host application, e.g. if plug-in editor is
-                * doing mouse tracking in a modal loop. This a is multithread app,
-                * we don't need it. */
-
-               case audioMasterIdle:
-                       return 0;
-
-               /* 6 - tells the host that the plugin is an instrument. Deprecated. */
-
-               case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
-                       return 0;
-
-               /* 7 - time infos */
-
-               case audioMasterGetTime:
-                       vstTimeInfo.samplePos          = G_Mixer.actualFrame;
-                       vstTimeInfo.sampleRate         = G_Conf.samplerate;
-                       vstTimeInfo.tempo              = G_Mixer.bpm;
-                       vstTimeInfo.timeSigNumerator   = G_Mixer.beats;
-                       vstTimeInfo.timeSigDenominator = G_Mixer.bars;
-                       vstTimeInfo.ppqPos             = (G_Mixer.actualFrame / (float) G_Conf.samplerate) * (float) G_Mixer.bpm / 60.0f;
-                       return (VstIntPtr) &vstTimeInfo;
-
-               /* ? - requires a pointer to VstEvents. No vstEvents so far (v0.5.4) */
-
-               case audioMasterProcessEvents:
-                       return 0;
-
-               /* 13 - tells that numInputs/numOutputs are changed. Not supported and
-                * not needed. */
-
-               case audioMasterIOChanged:
-                       return false;
-
-               /* 14 - plugin needs idle calls (outside its editor window). Deprecated */
-
-               case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
-                       return 0;
-
-               /* 15 - requests to resize the editor window. w = index, h = value*/
-
-               case audioMasterSizeWindow: {
-                       gWindow *window = NULL;
-                       for (unsigned i=0; i<masterOut.size && !window; i++)
-                               if (masterOut.at(i)->getPlugin() == effect)
-                                       window = masterOut.at(i)->window;
-
-                       for (unsigned i=0; i<masterIn.size && !window; i++)
-                               if (masterIn.at(i)->getPlugin() == effect)
-                                       window = masterIn.at(i)->window;
-
-                       for (unsigned i=0; i<G_Mixer.channels.size && !window; i++) {
-                               Channel *ch = G_Mixer.channels.at(i);
-                               for (unsigned j=0; j<ch->plugins.size && !window; j++)
-                                       if (ch->plugins.at(j)->getPlugin() == effect)
-                                               window = ch->plugins.at(j)->window;
-                       }
-
-                       if (window) {
-                               gLog("[pluginHost] audioMasterSizeWindow: resizing window from plugin %p\n", (void*) effect);
-                               if (index == 1 || value == 1)
-                                       gLog("[pluginHost] warning: non-sense values!\n");
-                               else
-                                       window->size((int)index, (int)value);
-                               return 1;
-                       }
-                       else {
-                               gLog("[pluginHost] audioMasterSizeWindow: window from plugin %p not found\n", (void*) effect);
-                               return 0;
-                       }
-               }
-
-               /* 16 - sample rate */
-
-               case audioMasterGetSampleRate:
-                       return G_Conf.samplerate;
-
-               /* ?? - buffer size */
-
-               case audioMasterGetBlockSize:
-                       return kernelAudio::realBufsize;
-
-               case audioMasterGetInputLatency:
-                       gLog("[pluginHost] requested opcode 'audioMasterGetInputLatency' (%d)\n", opcode);
-                       return 0;
-
-               case audioMasterGetOutputLatency:
-                       gLog("[pluginHost] requested opcode 'audioMasterGetOutputLatency' (%d)\n", opcode);
-                       return 0;
-
-               /* 23 - wants to know what kind of process is that.
-                * kVstProcessLevelRealtime = currently in audio thread (where
-                * process is called). */
-
-               case audioMasterGetCurrentProcessLevel:
-                       return kVstProcessLevelRealtime;
-
-               /* 32 - vendor name */
-
-               case audioMasterGetVendorString:
-                       strcpy((char*)ptr, "Monocasual");
-                       return 1;
-
-               /* 32 - product name */
-
-               case audioMasterGetProductString:
-                       strcpy((char*)ptr, "Giada");
-                       return 1;
-
-               /* 33 - product version */
-
-               case audioMasterGetVendorVersion:
-                       return (int) VERSIONE_FLOAT * 100;
-
-
-               /* 37 - Plugin asks Host if it implements the feature text. */
-
-               case audioMasterCanDo:
-                       gLog("[pluginHost] audioMasterCanDo: %s\n", (char*)ptr);
-                       if (!strcmp((char*)ptr, "sizeWindow")       ||
-                                       !strcmp((char*)ptr, "sendVstTimeInfo")  ||
-                                       !strcmp((char*)ptr, "sendVstMidiEvent") ||
-                                       !strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime"))
-                               return 1; // we can do all of that
-                       else
-                               return 0;
-
-               /* 42 - Something has changed, update the host's 'multi-fx' display.
-                * Not supported right now, return 0. This opcode deals with the program
-                * changes, more infos http://www.asseca.com/vst-24-specs/amUpdateDisplay.html */
-
-               case audioMasterUpdateDisplay:
-                       return 0;
-
-               case audioMasterGetLanguage:
-                       return kVstLangEnglish;
-
-               /* ?? */
-
-               case audioMasterGetAutomationState:
-                       gLog("[pluginHost] requested opcode 'audioMasterGetAutomationState' (%d)\n", opcode);
-                       return 0;
-
-               /* 43 - It tells the Host that if it needs to, it has to record
-                * automation data for this control. In other words this opcode is fired
-                * when the user starts to tweak a parameter with the mouse.
-                * Useful when the plugin actions will be recorded. */
-
-               case audioMasterBeginEdit:
-                       return 0;
-
-               /* 44 - no more interaction for the user, started with the previous
-                * opcode. */
-
-               case audioMasterEndEdit:
-                       return 0;
-
-               default:
-                       gLog("[pluginHost] FIXME: host callback called with opcode %d\n", opcode);
-                       return 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) {
-
-       Plugin *p    = new Plugin();
-       bool success = true;
-
-       gVector <Plugin *> *pStack;
-       pStack = getStack(stackType, ch);
-
-       if (!p->load(fname)) {
-               //delete p;
-               //return 0;
-               success = false;
-       }
-
-       /* if the load failed we add a 'dead' plugin into the stack. This is
-        * useful to report a missing plugin. */
-
-       if (!success) {
-               pStack->add(p);
-               return 0;
-       }
-
-       /* otherwise let's try to initialize it. */
-
-       else {
-
-               /* try to init the plugin. If fails, delete it and return error. */
-
-               if (!p->init(&PluginHost::HostCallback)) {
-                       delete p;
-                       return 0;
-               }
-
-               /* plugin setup */
-
-               p->setup(G_Conf.samplerate, kernelAudio::realBufsize);
-
-               /* try to add the new plugin until succeed */
-
-               int lockStatus;
-               while (true) {
-                       lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
-                       if (lockStatus == 0) {
-                               pStack->add(p);
-                               pthread_mutex_unlock(&G_Mixer.mutex_plugins);
-                               break;
-                       }
-               }
-
-               char name[256]; p->getName(name);
-               gLog("[pluginHost] plugin id=%d loaded (%s), stack type=%d, stack size=%d\n", p->getId(), name, stackType, pStack->size);
-
-               /* p->resume() is suggested. Who knows... */
-
-               p->resume();
-
-               return 1;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::processStack(float *buffer, int stackType, Channel *ch) {
-
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-
-       /* empty stack, stack not found or mixer not ready: do nothing */
-       /// TODO - join evaluation
-
-       if (!G_Mixer.ready)
-               return;
-       if (pStack == NULL)
-               return;
-       if (pStack->size == 0)
-               return;
-
-       /* converting buffer from Giada to VST */
-
-       for (unsigned i=0; i<kernelAudio::realBufsize; i++) {
-               bufferI[0][i] = buffer[i*2];
-               bufferI[1][i] = buffer[(i*2)+1];
-       }
-
-       /* hardcore processing. At the end we swap input and output, so that
-        * the N-th plugin will process the result of the plugin N-1. */
-
-       for (unsigned i=0; i<pStack->size; i++) {
-               /// TODO - join evaluation
-
-               if (pStack->at(i)->status != 1)
-                       continue;
-               if (pStack->at(i)->suspended)
-                       continue;
-               if (pStack->at(i)->bypass)
-                       continue;
-               if (ch) {   // process events if it's a channel stack
-                       if (ch->type == CHANNEL_MIDI) {
-                               ///gLog("events: %d\n", (((MidiChannel*)ch)->getVstEvents())->numEvents);
-                               pStack->at(i)->processEvents(((MidiChannel*)ch)->getVstEvents());
-                       }
-               }
-               pStack->at(i)->processAudio(bufferI, bufferO, kernelAudio::realBufsize);
-               bufferI = bufferO;
-       }
-
-       /* converting buffer from VST to Giada. A note for the future: if we
-        * overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */
-
-       for (unsigned i=0; i<kernelAudio::realBufsize; i++) {
-               buffer[i*2]     = bufferO[0][i];
-               buffer[(i*2)+1] = bufferO[1][i];
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::processStackOffline(float *buffer, int stackType, Channel *ch, int size) {
-
-       /* call processStack on the entire size of the buffer. How many cycles?
-        * size / (kernelAudio::realBufsize*2) (ie. internal bufsize) */
-
-       /** FIXME 1 - calling processStack is slow, due to its internal buffer
-        * conversions. We should also call processOffline from VST sdk */
-
-       int index = 0;
-       int step  = kernelAudio::realBufsize*2;
-
-       while (index <= size) {
-               int left = index+step-size;
-               if (left < 0)
-                       processStack(&buffer[index], stackType, ch);
-
-       /** FIXME 2 - we left out the last part of buffer, because size % step != 0.
-        * we should process the last chunk in a separate buffer, padded with 0 */
-
-               //else
-               //      gLog("chunk of buffer left, size=%d\n", left);
-
-               index+=step;
-       }
-
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Plugin *PluginHost::getPluginById(int id, int stackType, Channel *ch) {
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-       for (unsigned i=0; i<pStack->size; i++) {
-               if (pStack->at(i)->getId() == id)
-                       return pStack->at(i);
-       }
-       return NULL;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Plugin *PluginHost::getPluginByIndex(int index, int stackType, Channel *ch) {
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-       if (pStack->size == 0)
-               return NULL;
-       if ((unsigned) index >= pStack->size)
-               return NULL;
-       return pStack->at(index);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::freeStack(int stackType, Channel *ch) {
-
-       gVector <Plugin *> *pStack;
-       pStack = getStack(stackType, ch);
-
-       if (pStack->size == 0)
-               return;
-
-       int lockStatus;
-       while (true) {
-               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
-               if (lockStatus == 0) {
-                       for (unsigned i=0; i<pStack->size; i++) {
-                               if (pStack->at(i)->status == 1) {  // only if plugin is ok
-                                       pStack->at(i)->suspend();
-                                       pStack->at(i)->close();
-                               }
-                               delete pStack->at(i);
-                       }
-                       pStack->clear();
-                       pthread_mutex_unlock(&G_Mixer.mutex_plugins);
-                       break;
-               }
-       }
-
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::freeAllStacks() {
-       freeStack(PluginHost::MASTER_OUT);
-       freeStack(PluginHost::MASTER_IN);
-       for (unsigned i=0; i<G_Mixer.channels.size; i++)
-               freeStack(PluginHost::CHANNEL, G_Mixer.channels.at(i));
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::freePlugin(int id, int stackType, Channel *ch) {
-
-       gVector <Plugin *> *pStack;
-       pStack = getStack(stackType, ch);
-
-       /* try to delete the plugin until succeed. G_Mixer has priority. */
-
-       for (unsigned i=0; i<pStack->size; i++)
-               if (pStack->at(i)->getId() == id) {
-
-                       if (pStack->at(i)->status == 0) { // no frills if plugin is missing
-                               delete pStack->at(i);
-                               pStack->del(i);
-                               return;
-                       }
-                       else {
-                               int lockStatus;
-                               while (true) {
-                                       lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
-                                       if (lockStatus == 0) {
-                                               pStack->at(i)->suspend();
-                                               pStack->at(i)->close();
-                                               delete pStack->at(i);
-                                               pStack->del(i);
-                                               pthread_mutex_unlock(&G_Mixer.mutex_plugins);
-                                               gLog("[pluginHost] plugin id=%d removed\n", id);
-                                               return;
-                                       }
-                                       //else
-                                               //gLog("[pluginHost] waiting for mutex...\n");
-                               }
-                       }
-               }
-       gLog("[pluginHost] plugin id=%d not found\n", id);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, Channel *ch) {
-
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-
-       int lockStatus;
-       while (true) {
-               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins);
-               if (lockStatus == 0) {
-                       pStack->swap(indexA, indexB);
-                       pthread_mutex_unlock(&G_Mixer.mutex_plugins);
-                       gLog("[pluginHost] plugin at index %d and %d swapped\n", indexA, indexB);
-                       return;
-               }
-               //else
-                       //gLog("[pluginHost] waiting for mutex...\n");
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int PluginHost::getPluginIndex(int id, int stackType, Channel *ch) {
-
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-
-       for (unsigned i=0; i<pStack->size; i++)
-               if (pStack->at(i)->getId() == id)
-                       return i;
-       return -1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gVector <Plugin *> *PluginHost::getStack(int stackType, Channel *ch) {
-       switch(stackType) {
-               case MASTER_OUT:
-                       return &masterOut;
-               case MASTER_IN:
-                       return &masterIn;
-               case CHANNEL:
-                       return &ch->plugins;
-               default:
-                       return NULL;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-VstMidiEvent *PluginHost::createVstMidiEvent(uint32_t msg)
-{
-       VstMidiEvent *e = (VstMidiEvent*) malloc(sizeof(VstMidiEvent));
-
-       /* type = two types of events: MIDI event and MIDI system exclusive
-        * (aka sysex, not implemented). */
-
-       e->type     = kVstMidiType;
-       e->byteSize = sizeof(VstMidiEvent);
-
-       /* deltaFrames = sample frames related to the current block start
-        * sample position. */
-
-       e->deltaFrames = 0;
-
-       /* flags = kVstMidiEventIsRealtime means that this event is played
-        * live (not in playback from a sequencer track). This allows the
-        * Plug-In to handle these flagged events with higher priority,
-        * especially when the Plug-In has a big latency */
-
-       e->flags = kVstMidiEventIsRealtime;
-
-       /* midiData = 1 to 3 MIDI bytes; midiData[3] is reserved (zero) */
-
-       e->midiData[0] = kernelMidi::getB1(msg); // note on/off + channel
-       e->midiData[1] = kernelMidi::getB2(msg); // note number
-       e->midiData[2] = kernelMidi::getB3(msg); // velocity
-       e->midiData[3] = 0;
-
-       /* noteLength = (in sample frames) of entire note, if available,
-        * else 0 */
-
-       e->noteLength = 0;
-
-       /* noteOffset = offset (in sample frames) into note from note start
-        * if available, else 0 */
-
-       e->noteOffset = 0;
-
-       /* noteOffVelocity =  Note Off Velocity [0, 127]. */
-
-       e->noteOffVelocity = 0;
-
-       return e;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-unsigned PluginHost::countPlugins(int stackType, Channel *ch) {
-       gVector <Plugin *> *pStack = getStack(stackType, ch);
-       return pStack->size;
-}
-
-
-#endif // #ifdef WITH_VST
diff --git a/src/pluginHost.h b/src/pluginHost.h
deleted file mode 100644 (file)
index 9b4db08..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * pluginHost
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifdef WITH_VST
-
-#ifndef __PLUGIN_HOST_
-#define __PLUGIN_HOST_
-
-#include "ge_window.h"
-#include "plugin.h"
-#include "utils.h"
-#include "init.h"
-#include "const.h"
-
-
-class PluginHost {
-
-private:
-
-       /* VSTs have a different buffer model:
-        *
-        * buffer[0] = channel left
-        * buffer[1] = channel right
-        * buffer[0][....] = all signals from left chan
-        * buffer[1][....] = all signals from right chan */
-
-       float **bufferI;
-       float **bufferO;
-
-       /* VST struct containing infos on tempo (bpm, freq, smtpe, ...). */
-
-       VstTimeInfo vstTimeInfo;
-
-public:
-
-       /* stack types. Use them together with getStack() in order to geta
-        * pointer to the right stack. */
-
-       enum stackType {
-               MASTER_OUT,
-               MASTER_IN,
-               CHANNEL
-       };
-
-       /* stack of Plugins */
-
-       gVector <Plugin *> masterOut;
-       gVector <Plugin *> masterIn;
-
-       PluginHost();
-       ~PluginHost();
-
-       int allocBuffers();
-
-       /* The plugin can ask the host if it supports a given capability,
-        * which is done through the HostCallback() function.
-        *
-        * Why static? This is a callback attached to each plugin in the stack
-        * and C++ callback functions need to be static when declared in class.
-        *
-        * OPCODE LIST:
-        * base version: vstsdk2.4/pluginterfaces/aeffect.h (vst 1.x)
-        * enhanced v. : vstsdk2.4/pluginterfaces/effectx.h (vst 2.x) */
-
-       static VstIntPtr VSTCALLBACK HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt);
-       VstIntPtr gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt);
-
-       int addPlugin(const char *fname, int stackType, class Channel *ch=NULL);
-
-       void processEvents(float *buffer, class Channel *ch);
-
-       /* processStack
-        * apply the fx list to the buffer. */
-
-       void processStack(float *buffer, int stackType, class Channel *ch=NULL);
-
-       /* processStackOffline
-        * apply the fx list to a longer chunk of data */
-
-       void processStackOffline(float *buffer, int stackType, class Channel *ch, int size);
-
-       /* createVstMidiEvent
-        * return a pointer to a new VstMidiEvent structure. */
-
-       VstMidiEvent *createVstMidiEvent(uint32_t msg);
-
-       gVector <Plugin *> *getStack(int stackType, class Channel *ch=NULL);
-
-       Plugin *getPluginById(int id, int stackType, class Channel *ch=NULL);
-
-       Plugin *getPluginByIndex(int index, int stackType, class Channel *ch=NULL);
-
-       int getPluginIndex(int id, int stackType, class Channel *ch=NULL);
-
-       unsigned countPlugins(int stackType, class Channel *ch=NULL);
-
-       void freeStack(int stackType, class Channel *ch=NULL);
-
-       void freeAllStacks();
-
-       void freePlugin(int id, int stackType, class Channel *ch=NULL);
-
-       void swapPlugin(unsigned indexA, unsigned indexB, int stackType, class Channel *ch=NULL);
-};
-#endif
-
-#endif // #ifdef WITH_VST
diff --git a/src/recorder.cpp b/src/recorder.cpp
deleted file mode 100644 (file)
index a0c8f0d..0000000
+++ /dev/null
@@ -1,698 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * recorder
- * Action recorder.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <math.h>
-#include "recorder.h"
-#include "const.h"
-#include "utils.h"
-#include "mixer.h"
-#include "mixerHandler.h"
-#include "kernelAudio.h"
-#include "pluginHost.h"
-#include "kernelMidi.h"
-#include "utils.h"
-#include "patch.h"
-#include "conf.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "log.h"
-
-
-#ifdef WITH_VST
-extern PluginHost G_PluginHost;
-#endif
-
-
-extern Mixer G_Mixer;
-extern Patch f_patch;
-extern Conf     G_Conf;
-
-
-namespace recorder
-{
-gVector<int> frames;
-gVector< gVector<action*> > global;
-gVector<action*>  actions;
-
-bool active = false;
-bool sortedActions = false;
-
-composite cmp;
-
-
-/* ------------------------------------------------------------------ */
-
-
-void init()
-{
-       sortedActions = false;
-       active = false;
-       clearAll();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool canRec(Channel *ch)
-{
-       /* NO recording if:
-        * recorder is inactive
-        * mixer is not running
-        * mixer is recording a take in this channel ch
-        * channel is empty */
-
-       if (!active || !G_Mixer.running || G_Mixer.chanInput == ch || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL))
-               return 0;
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void rec(int index, int type, int frame, uint32_t iValue, float fValue)
-{
-       /* make sure frame is even */
-
-       if (frame % 2 != 0)
-               frame++;
-
-       /* allocating the action */
-
-       action *a = (action*) malloc(sizeof(action));
-       a->chan   = index;
-       a->type   = type;
-       a->frame  = frame;
-       a->iValue = iValue;
-       a->fValue = fValue;
-
-       /* check if the frame exists in the stack. If it exists, we don't extend
-        * the stack, but we add (or push) a new action to it. */
-
-       int frameToExpand = frames.size;
-       for (int i=0; i<frameToExpand; i++)
-               if (frames.at(i) == frame) {
-                       frameToExpand = i;
-                       break;
-               }
-
-       /* espansione dello stack frames nel caso l'azione ricada in frame
-        * non precedentemente memorizzati (frameToExpand == frames.size).
-        * Espandere frames è facile, basta aggiungere un frame in coda.
-        * Espandere global è più complesso: bisogna prima allocare una
-        * cella in global (per renderlo parallelo a frames) e poi
-        * inizializzare il suo sub-stack (di action). */
-
-       if (frameToExpand == (int) frames.size) {
-               frames.add(frame);
-               global.add(actions);                                                    // array of actions added
-               global.at(global.size-1).add(a);        // action added
-       }
-       else {
-
-               /* no duplicates, please */
-
-               for (unsigned t=0; t<global.at(frameToExpand).size; t++) {
-                       action *ac = global.at(frameToExpand).at(t);
-                       if (ac->chan   == index  &&
-                           ac->type   == type   &&
-                           ac->frame  == frame  &&
-                           ac->iValue == iValue &&
-                           ac->fValue == fValue)
-                               return;
-               }
-
-               global.at(frameToExpand).add(a);                // expand array
-       }
-
-       /* if WITH_VST create a new VST event and attach it to our action.
-        * Nota bene: the VST event occurs on localFrame=0: this is a
-        * user-generated event after all! */
-
-#ifdef WITH_VST
-       if (type == ACTION_MIDI)
-               a->event = G_PluginHost.createVstMidiEvent(a->iValue);
-#endif
-
-       /* don't activate the channel (readActions == false), it's up to
-        * the other layers */
-
-       Channel *ch = G_Mixer.getChannelByIndex(index);
-       ch->hasActions = true;
-
-       sortedActions = false;
-
-       gLog("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
-               a->type, a->frame, a->chan, a->iValue, a->iValue, a->fValue);
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void clearChan(int index)
-{
-       gLog("[REC] clearing chan %d...\n", index);
-
-       for (unsigned i=0; i<global.size; i++) {        // for each frame i
-               unsigned j=0;
-               while (true) {
-                       if (j == global.at(i).size) break;        // for each action j of frame i
-                       action *a = global.at(i).at(j);
-                       if (a->chan == index)   {
-#ifdef WITH_VST
-                               if (a->type == ACTION_MIDI)
-                                       free(a->event);
-#endif
-                               free(a);
-                               global.at(i).del(j);
-                       }
-                       else
-                               j++;
-               }
-       }
-
-       Channel *ch = G_Mixer.getChannelByIndex(index);
-       ch->hasActions = false;
-       optimize();
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void clearAction(int index, char act)
-{
-       gLog("[REC] clearing action %d from chan %d...\n", act, index);
-       for (unsigned i=0; i<global.size; i++) {                                                // for each frame i
-               unsigned j=0;
-               while (true) {                                   // for each action j of frame i
-                       if (j == global.at(i).size)
-                               break;
-                       action *a = global.at(i).at(j);
-                       if (a->chan == index && (act & a->type) == a->type)     { // bitmask
-                               free(a);
-                               global.at(i).del(j);
-                       }
-                       else
-                               j++;
-               }
-       }
-       Channel *ch = G_Mixer.getChannelByIndex(index);
-       ch->hasActions = false;   /// FIXME - why this? Isn't it useless if we call chanHasActions?
-       optimize();
-       chanHasActions(index);    /// FIXME
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue, float fValue)
-{
-       /* make sure frame is even */
-
-       if (frame % 2 != 0)
-               frame++;
-               
-       /* find the frame 'frame' */
-
-       bool found = false;
-       for (unsigned i=0; i<frames.size && !found; i++) {
-               if (frames.at(i) == frame) {
-
-                       /* find the action in frame i */
-
-                       for (unsigned j=0; j<global.at(i).size; j++) {
-                               action *a = global.at(i).at(j);
-
-                               /* action comparison logic */
-
-                               bool doit = (a->chan == chan && a->type == (type & a->type));
-                               if (checkValues)
-                                       doit &= (a->iValue == iValue && a->fValue == fValue);
-
-                               if (doit) {
-                                       int lockStatus = 0;
-                                       while (lockStatus == 0) {
-                                               lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs);
-                                               if (lockStatus == 0) {
-#ifdef WITH_VST
-                                                       if (type == ACTION_MIDI)
-                                                               free(a->event);
-#endif
-                                                       free(a);
-                                                       global.at(i).del(j);
-                                                       pthread_mutex_unlock(&G_Mixer.mutex_recs);
-                                                       found = true;
-                                                       break;
-                                               }
-                                               else
-                                                       gLog("[REC] delete action: waiting for mutex...\n");
-                                       }
-                               }
-                       }
-               }
-       }
-       if (found) {
-               optimize();
-               chanHasActions(chan);
-               gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
-                       type, frame, chan, iValue, iValue, fValue);
-       }
-       else
-               gLog("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
-                       type, frame, chan, iValue, iValue, fValue);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void deleteActions(int chan, int frame_a, int frame_b, char type)
-{
-       sortActions();
-       gVector<int> dels;
-
-       for (unsigned i=0; i<frames.size; i++)
-               if (frames.at(i) > frame_a && frames.at(i) < frame_b)
-                       dels.add(frames.at(i));
-
-       for (unsigned i=0; i<dels.size; i++)
-               deleteAction(chan, dels.at(i), type, false); // false == don't check values
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void clearAll()
-{
-       while (global.size > 0) {
-               for (unsigned i=0; i<global.size; i++) {
-                       for (unsigned k=0; k<global.at(i).size; k++) {
-#ifdef WITH_VST
-                               if (global.at(i).at(k)->type == ACTION_MIDI)
-                                       free(global.at(i).at(k)->event);
-#endif
-                               free(global.at(i).at(k));                                                                       // free action
-                       }
-                       global.at(i).clear();                                                                                           // free action container
-                       global.del(i);
-               }
-       }
-
-       for (unsigned i=0; i<G_Mixer.channels.size; i++) {
-               G_Mixer.channels.at(i)->hasActions  = false;
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
-                       ((SampleChannel*)G_Mixer.channels.at(i))->readActions = false;
-       }
-
-       global.clear();
-       frames.clear();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void optimize()
-{
-       /* do something until the i frame is empty. */
-
-       unsigned i = 0;
-       while (true) {
-               if (i == global.size) return;
-               if (global.at(i).size == 0) {
-                       global.del(i);
-                       frames.del(i);
-               }
-               else
-                       i++;
-       }
-
-       sortActions();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void sortActions()
-{
-       if (sortedActions)
-               return;
-       for (unsigned i=0; i<frames.size; i++)
-               for (unsigned j=0; j<frames.size; j++)
-                       if (frames.at(j) > frames.at(i)) {
-                               frames.swap(j, i);
-                               global.swap(j, i);
-                       }
-       sortedActions = true;
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void updateBpm(float oldval, float newval, int oldquanto)
-{
-       for (unsigned i=0; i<frames.size; i++) {
-
-               float frame  = ((float) frames.at(i)/newval) * oldval;
-               frames.at(i) = (int) frame;
-
-               /* the division up here cannot be precise. A new frame can be 44099
-                * and the quantizer set to 44100. That would mean two recs completely
-                * useless. So we compute a reject value ('scarto'): if it's lower
-                * than 6 frames the new frame is collapsed with a quantized frame. */
-               /** CHECKME - maybe 6 frames are too low */
-
-               if (frames.at(i) != 0) {
-                       int scarto = oldquanto % frames.at(i);
-                       if (scarto > 0 && scarto <= 6)
-                               frames.at(i) = frames.at(i) + scarto;
-               }
-
-               /* never ever have odd frames. */
-
-               if (frames.at(i) % 2 != 0)
-                       frames.at(i)++;
-       }
-
-       /* update structs */
-
-       for (unsigned i=0; i<frames.size; i++) {
-               for (unsigned j=0; j<global.at(i).size; j++) {
-                       action *a = global.at(i).at(j);
-                       a->frame = frames.at(i);
-               }
-       }
-
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void updateSamplerate(int systemRate, int patchRate)
-{
-       /* diff ratio: systemRate / patchRate
-        * e.g.  44100 / 96000 = 0.4... */
-
-       if (systemRate == patchRate)
-               return;
-
-       gLog("[REC] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate);
-
-       float ratio = systemRate / (float) patchRate;
-       for (unsigned i=0; i<frames.size; i++) {
-
-               gLog("[REC]    oldFrame = %d", frames.at(i));
-
-               float newFrame = frames.at(i);
-               newFrame = floorf(newFrame * ratio);
-
-               frames.at(i) = (int) newFrame;
-
-               if (frames.at(i) % 2 != 0)
-                       frames.at(i)++;
-
-               gLog(", newFrame = %d\n", frames.at(i));
-       }
-
-       /* update structs */
-
-       for (unsigned i=0; i<frames.size; i++) {
-               for (unsigned j=0; j<global.at(i).size; j++) {
-                       action *a = global.at(i).at(j);
-                       a->frame = frames.at(i);
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void expand(int old_fpb, int new_fpb)
-{
-       /* this algorithm requires multiple passages if we expand from e.g. 2
-        * to 16 beats, precisely 16 / 2 - 1 = 7 times (-1 is the first group,
-        * which exists yet). If we expand by a non-multiple, the result is zero,
-        * due to float->int implicit cast */
-
-       unsigned pass = (int) (new_fpb / old_fpb) - 1;
-       if (pass == 0) pass = 1;
-
-       unsigned init_fs = frames.size;
-
-       for (unsigned z=1; z<=pass; z++) {
-               for (unsigned i=0; i<init_fs; i++) {
-                       unsigned newframe = frames.at(i) + (old_fpb*z);
-                       frames.add(newframe);
-                       global.add(actions);
-                       for (unsigned k=0; k<global.at(i).size; k++) {
-                               action *a = global.at(i).at(k);
-                               rec(a->chan, a->type, newframe, a->iValue, a->fValue);
-                       }
-               }
-       }
-       gLog("[REC] expanded recs\n");
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void shrink(int new_fpb)
-{
-       /* easier than expand(): here we delete eveything beyond old_framesPerBars. */
-
-       unsigned i=0;
-       while (true) {
-               if (i == frames.size) break;
-
-               if (frames.at(i) >= new_fpb) {
-                       for (unsigned k=0; k<global.at(i).size; k++)
-                               free(global.at(i).at(k));                       // free action
-                       global.at(i).clear();                                                           // free action container
-                       global.del(i);                                                                                  // shrink global
-                       frames.del(i);                                                                                  // shrink frames
-               }
-               else
-                       i++;
-       }
-       optimize();
-       gLog("[REC] shrinked recs\n");
-       //print();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void chanHasActions(int index)
-{
-       Channel *ch = G_Mixer.getChannelByIndex(index);
-       if (global.size == 0) {
-               ch->hasActions = false;
-               return;
-       }
-       for (unsigned i=0; i<global.size && !ch->hasActions; i++) {
-               for (unsigned j=0; j<global.at(i).size && !ch->hasActions; j++) {
-                       if (global.at(i).at(j)->chan == index)
-                               ch->hasActions = true;
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue)
-{
-       sortActions();  // mandatory
-
-       unsigned i=0;
-       while (i < frames.size && frames.at(i) <= frame) i++;
-
-       if (i == frames.size)   // no further actions past 'frame'
-               return -1;
-
-       for (; i<global.size; i++)
-               for (unsigned j=0; j<global.at(i).size; j++) {
-                       action *a = global.at(i).at(j);
-                       if (a->chan == chan && (type & a->type) == a->type) {
-                               if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) {
-                                       *out = global.at(i).at(j);
-                                       return 1;
-                               }
-                       }
-               }
-
-       return -2;   // no 'type' actions found
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int getAction(int chan, char action, int frame, struct action **out)
-{
-       for (unsigned i=0; i<global.size; i++)
-               for (unsigned j=0; j<global.at(i).size; j++)
-                       if (frame  == global.at(i).at(j)->frame &&
-                                       action == global.at(i).at(j)->type &&
-                                       chan   == global.at(i).at(j)->chan)
-                       {
-                               *out = global.at(i).at(j);
-                               return 1;
-                       }
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void startOverdub(int index, char actionMask, int frame)
-{
-       /* prepare the composite struct */
-
-       if (actionMask == ACTION_KEYS) {
-               cmp.a1.type = ACTION_KEYPRESS;
-               cmp.a2.type = ACTION_KEYREL;
-       }
-       else {
-               cmp.a1.type = ACTION_MUTEON;
-               cmp.a2.type = ACTION_MUTEOFF;
-       }
-       cmp.a1.chan  = index;
-       cmp.a2.chan  = index;
-       cmp.a1.frame = frame;
-       // cmp.a2.frame doesn't exist yet
-
-       /* avoid underlying action truncation: if action2.type == nextAction:
-        * you are in the middle of a composite action, truncation needed */
-
-       rec(index, cmp.a1.type, frame);
-
-       action *act = NULL;
-       int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act);
-       if (res == 1) {
-               if (act->type == cmp.a2.type) {
-                       int truncFrame = cmp.a1.frame-kernelAudio::realBufsize;
-                       if (truncFrame < 0)
-                               truncFrame = 0;
-                       gLog("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type);
-                       rec(index, cmp.a2.type, truncFrame);
-               }
-       }
-
-       SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(index);
-       ch->readActions = false;   // don't use disableRead()
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void stopOverdub(int frame)
-{
-       cmp.a2.frame  = frame;
-       bool ringLoop = false;
-       bool nullLoop = false;
-
-       /* ring loop verification, i.e. a composite action with key_press at
-        * frame N and key_release at frame M, with M <= N */
-
-       if (cmp.a2.frame < cmp.a1.frame) {
-               ringLoop = true;
-               gLog("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
-               rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames);     // record at the end of the sequencer
-       }
-       else
-       if (cmp.a2.frame == cmp.a1.frame) {
-               nullLoop = true;
-               gLog("[REC]  null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
-               deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values
-       }
-
-       SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(cmp.a2.chan);
-       ch->readActions = false;      // don't use disableRead()
-
-       /* remove any nested action between keypress----keyrel, then record */
-
-       if (!nullLoop)
-               deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type);
-               deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type);
-
-       if (!ringLoop && !nullLoop) {
-               rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
-
-               /* avoid underlying action truncation, if keyrel happens inside a
-               * composite action */
-
-               action *act = NULL;
-               int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act);
-               if (res == 1) {
-                       if (act->type == cmp.a2.type) {
-                               gLog("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type);
-                               deleteAction(act->chan, act->frame, act->type, false); // false == don't check values
-                       }
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void print()
-{
-       gLog("[REC] ** print debug **\n");
-       for (unsigned i=0; i<global.size; i++) {
-               gLog("  frame %d\n", frames.at(i));
-               for (unsigned j=0; j<global.at(i).size; j++) {
-                       gLog("    action %d | chan %d | frame %d\n", global.at(i).at(j)->type, global.at(i).at(j)->chan, global.at(i).at(j)->frame);
-               }
-       }
-}
-
-} // namespace
diff --git a/src/recorder.h b/src/recorder.h
deleted file mode 100644 (file)
index 0fd378d..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * recorder
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef RECORDER_H
-#define RECORDER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "utils.h"
-#include "const.h"
-#include "mixer.h"
-
-#ifdef WITH_VST
-
-/* before including aeffetx(x).h we must define __cdecl, otherwise VST
- * headers can't be compiled correctly. In windows __cdecl is already
- * defined. */
-
-       #ifdef __GNUC__
-               #ifndef _WIN32
-                       #define __cdecl
-               #endif
-       #endif
-       #include "vst/aeffectx.h"
-#endif
-
-/*
- * [global0]-->[gVector<_action*>0]-->[a0][a1][a2]                             0[frames1]
- * [global1]-->[gVector<_action*>1]-->[a0][a1][a2]                             1[frames2]
- * [global2]-->[gVector<_action*>2]-->[a0][a1][a2]                             2[frames3]
- * [global3]-->[gVector<_action*>3]-->[a0][a1][a2]                             3[frames4]
- * */
-
-namespace recorder {
-
-/* action
- * struct containing fields to describe an atomic action. Note from
- * VST sdk: parameter values, like all VST parameters, are declared as
- * floats with an inclusive range of 0.0 to 1.0 (fValue). */
-
-struct action {
-       int      chan;    // channel index, i.e. Channel->index
-       int      type;
-       int      frame;   // redundant info, used by helper functions
-       float    fValue;  // used only for envelopes (volumes, vst params).
-       uint32_t iValue;  // used only for MIDI events
-
-       /* if VST store here a pointer to a vstEvent. */
-
-#ifdef WITH_VST
-       VstMidiEvent *event;
-#endif
-};
-
-/* composite
- * a group of two actions (keypress+keyrel, muteon+muteoff) used during
- * the overdub process */
-
-struct composite {
-       action a1;
-       action a2;
-};
-
-extern gVector<int>  frames;                                         // frame counter (sentinel) frames.size == global.size
-extern gVector< gVector<action*> > global;     // container of containers of actions
-extern gVector<action*>  actions;                                  // container of actions
-
-extern bool active;
-extern bool sortedActions;                  // are actions sorted via sortActions()?
-
-/* init
- * everything starts from here. */
-
-void init();
-
-/* chanHasActions
- * Check if the channel has at least one action recorded. If false, sets
- * ch->hasActions = false. Used after an action deletion. */
-
-void chanHasActions(int chan);
-
-/* canRec
- * can a channel rec an action? Call this one BEFORE rec(). */
-
-bool canRec(Channel *ch);
-
-/* rec
- * record an action. */
-
-void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f);
-
-/* clearChan
- * clear all actions from a channel. */
-
-void clearChan(int chan);
-
-/* clearAction
- * clear the 'action' action type from a channel. */
-
-void clearAction(int chan, char action);
-
-/* deleteAction
- * delete ONE action. Useful in the action editor. 'type' can be a mask. */
-
-void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue=0, float fValue=0.0);
-
-/* deleteActions
- * delete A RANGE of actions from frame_a to frame_b in channel 'chan'.
- * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */
-
-void deleteActions(int chan, int frame_a, int frame_b, char type);
-
-/* clearAll
- * delete everything. */
-
-void clearAll();
-
-/* optimize
- * clear frames without actions. */
-
-void optimize();
-
-/* sortActions
- * sorts actions by frame, asc mode. */
-
-void sortActions();
-
-/* updateBpm
- * reassign frames by calculating the new bpm value. */
-
-void updateBpm(float oldval, float newval, int oldquanto);
-
-/* updateSamplerate
- * reassign frames taking in account the samplerate. If f_system ==
- * f_patch nothing changes, otherwise the conversion is mandatory. */
-
-void updateSamplerate(int systemRate, int patchRate);
-
-void expand(int old_fpb, int new_fpb);
-void shrink(int new_fpb);
-
-/* getNextAction
- * return the nearest action in chan 'chan' of type 'action' starting
- * from 'frame'. Action can be a bitmask. If iValue != -1 search for
- * next action with iValue == iValue: useful for MIDI key_release. */
-
-int getNextAction(int chan, char action, int frame, struct action **out, uint32_t iValue=0);
-
-/* getAction
- * return a pointer to action in chan 'chan' of type 'action' at frame
- * 'frame'. */
-
-int getAction(int chan, char action, int frame, struct action **out);
-
-/* start/endOverdub */
-
-void startOverdub(int chan, char action, int frame);
-void stopOverdub(int frame);
-
-/* print
- * debug of the frame stack. */
-
-void print();
-
-}  // namespace
-
-#endif
diff --git a/src/resource.h b/src/resource.h
deleted file mode 100644 (file)
index d771ba8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#define IDI_ICON1 101
\ No newline at end of file
diff --git a/src/resource.rc b/src/resource.rc
deleted file mode 100644 (file)
index fb0be40..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "resource.h"
-IDI_ICON1 ICON DISCARDABLE "giada.ico"
\ No newline at end of file
diff --git a/src/rtaudio-mod/Makefile.in b/src/rtaudio-mod/Makefile.in
deleted file mode 100644 (file)
index 89cacdc..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in
-### RtAudio library Makefile
-
-RM = /bin/rm
-LN = /bin/ln
-
-OBJECTS        = RtAudio.o @objects@
-
-LIBNAME = librtaudio
-STATIC = $(LIBNAME).a
-SHARED = @sharedlib@
-RELEASE = 4.1.1
-MAJOR = 4
-LIBRARIES = $(STATIC) $(SHARED)
-
-CC       = @CXX@
-AR       = @AR@
-RANLIB   = @RANLIB@
-
-DEFS     = @CPPFLAGS@
-CFLAGS   = @CXXFLAGS@ -Iinclude -fPIC
-
-PREFIX   = @prefix@
-
-all : $(LIBRARIES)
-
-tests:
-       cd tests && $(MAKE) all
-
-$(LIBRARIES): $(OBJECTS)
-       $(AR) ruv $(STATIC) $(OBJECTS)
-       ranlib $(STATIC)
-       $(CC) -fPIC @libflags@ $(OBJECTS) @LIBS@
-       $(LN) -sf @sharedname@ $(SHARED)
-       $(LN) -sf @sharedname@ $(SHARED).$(MAJOR)
-
-%.o : %.cpp
-       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
-
-%.o : include/%.cpp
-       $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@
-
-install:
-       install --mode=755 $(STATIC) $(PREFIX)/lib/
-       install --mode=755 @sharedname@ $(PREFIX)/lib/
-       $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED)
-       $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED).$(MAJOR)
-       install --mode=644 $(LIBNAME).pc $(PREFIX)/lib/pkgconfig
-       install --mode=644 RtAudio.h $(PREFIX)/include/
-       install --mode=755 rtaudio-config $(PREFIX)/bin/
-
-uninstall:
-       -@rm -vf $(patsubst %,$(PREFIX)/lib/%, $(LIBRARIES) $(SHARED).$(MAJOR) $(SHARED).$(RELEASE))
-       -@rm -vf $(PREFIX)/lib/pkgconfig/$(LIBNAME).pc
-       -@rm -vf $(PREFIX)/bin/rtaudio-config
-
-clean : 
-       $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
-       $(RM) -f $(OBJECTS)
-       $(RM) -f *~
-       cd tests && $(MAKE) clean
-
-distclean:
-       $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
-       $(RM) -f $(OBJECTS)
-       $(RM) -f *~
-       $(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config $(LIBNAME).pc
-       cd tests && $(MAKE) distclean
-
-strip : 
-       strip $(LIBRARIES)
-       ranlib $(LIBRARIES)
-       cd tests && $(MAKE) strip
-
-.PHONY: clean distclean strip install uninstall
diff --git a/src/rtaudio-mod/RtAudio.cpp b/src/rtaudio-mod/RtAudio.cpp
deleted file mode 100644 (file)
index 5716c59..0000000
+++ /dev/null
@@ -1,10145 +0,0 @@
-/************************************************************************/\r
-/*! \class RtAudio\r
-    \brief Realtime audio i/o C++ classes.\r
-\r
-    RtAudio provides a common API (Application Programming Interface)\r
-    for realtime audio input/output across Linux (native ALSA, Jack,\r
-    and OSS), Macintosh OS X (CoreAudio and Jack), and Windows\r
-    (DirectSound, ASIO and WASAPI) operating systems.\r
-\r
-    RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
-\r
-    RtAudio: realtime audio i/o C++ classes\r
-    Copyright (c) 2001-2014 Gary P. Scavone\r
-\r
-    Permission is hereby granted, free of charge, to any person\r
-    obtaining a copy of this software and associated documentation files\r
-    (the "Software"), to deal in the Software without restriction,\r
-    including without limitation the rights to use, copy, modify, merge,\r
-    publish, distribute, sublicense, and/or sell copies of the Software,\r
-    and to permit persons to whom the Software is furnished to do so,\r
-    subject to the following conditions:\r
-\r
-    The above copyright notice and this permission notice shall be\r
-    included in all copies or substantial portions of the Software.\r
-\r
-    Any person wishing to distribute modifications to the Software is\r
-    asked to send the modifications to the original developer so that\r
-    they can be incorporated into the canonical version.  This is,\r
-    however, not a binding provision of this license.\r
-\r
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-/************************************************************************/\r
-\r
-// RtAudio: Version 4.1.1\r
-\r
-#include "RtAudio.h"\r
-#include <iostream>\r
-#include <cstdlib>\r
-#include <cstring>\r
-#include <climits>\r
-\r
-// Static variable definitions.\r
-const unsigned int RtApi::MAX_SAMPLE_RATES = 14;\r
-const unsigned int RtApi::SAMPLE_RATES[] = {\r
-  4000, 5512, 8000, 9600, 11025, 16000, 22050,\r
-  32000, 44100, 48000, 88200, 96000, 176400, 192000\r
-};\r
-\r
-#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)\r
-  #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)\r
-  #define MUTEX_DESTROY(A)    DeleteCriticalSection(A)\r
-  #define MUTEX_LOCK(A)       EnterCriticalSection(A)\r
-  #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)\r
-#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)\r
-  // pthread API\r
-  #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)\r
-  #define MUTEX_DESTROY(A)    pthread_mutex_destroy(A)\r
-  #define MUTEX_LOCK(A)       pthread_mutex_lock(A)\r
-  #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)\r
-#else\r
-  #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions\r
-  #define MUTEX_DESTROY(A)    abs(*A) // dummy definitions\r
-#endif\r
-\r
-// *************************************************** //\r
-//\r
-// RtAudio definitions.\r
-//\r
-// *************************************************** //\r
-\r
-std::string RtAudio :: getVersion( void ) throw()\r
-{\r
-  return RTAUDIO_VERSION;\r
-}\r
-\r
-void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()\r
-{\r
-  apis.clear();\r
-\r
-  // The order here will control the order of RtAudio's API search in\r
-  // the constructor.\r
-#if defined(__UNIX_JACK__)\r
-  apis.push_back( UNIX_JACK );\r
-#endif\r
-#if defined(__LINUX_ALSA__)\r
-  apis.push_back( LINUX_ALSA );\r
-#endif\r
-#if defined(__LINUX_PULSE__)\r
-  apis.push_back( LINUX_PULSE );\r
-#endif\r
-#if defined(__LINUX_OSS__)\r
-  apis.push_back( LINUX_OSS );\r
-#endif\r
-#if defined(__WINDOWS_ASIO__)\r
-  apis.push_back( WINDOWS_ASIO );\r
-#endif\r
-#if defined(__WINDOWS_WASAPI__)\r
-  apis.push_back( WINDOWS_WASAPI );\r
-#endif\r
-#if defined(__WINDOWS_DS__)\r
-  apis.push_back( WINDOWS_DS );\r
-#endif\r
-#if defined(__MACOSX_CORE__)\r
-  apis.push_back( MACOSX_CORE );\r
-#endif\r
-#if defined(__RTAUDIO_DUMMY__)\r
-  apis.push_back( RTAUDIO_DUMMY );\r
-#endif\r
-}\r
-\r
-void RtAudio :: openRtApi( RtAudio::Api api )\r
-{\r
-  if ( rtapi_ )\r
-    delete rtapi_;\r
-  rtapi_ = 0;\r
-\r
-#if defined(__UNIX_JACK__)\r
-  if ( api == UNIX_JACK )\r
-    rtapi_ = new RtApiJack();\r
-#endif\r
-#if defined(__LINUX_ALSA__)\r
-  if ( api == LINUX_ALSA )\r
-    rtapi_ = new RtApiAlsa();\r
-#endif\r
-#if defined(__LINUX_PULSE__)\r
-  if ( api == LINUX_PULSE )\r
-    rtapi_ = new RtApiPulse();\r
-#endif\r
-#if defined(__LINUX_OSS__)\r
-  if ( api == LINUX_OSS )\r
-    rtapi_ = new RtApiOss();\r
-#endif\r
-#if defined(__WINDOWS_ASIO__)\r
-  if ( api == WINDOWS_ASIO )\r
-    rtapi_ = new RtApiAsio();\r
-#endif\r
-#if defined(__WINDOWS_WASAPI__)\r
-  if ( api == WINDOWS_WASAPI )\r
-    rtapi_ = new RtApiWasapi();\r
-#endif\r
-#if defined(__WINDOWS_DS__)\r
-  if ( api == WINDOWS_DS )\r
-    rtapi_ = new RtApiDs();\r
-#endif\r
-#if defined(__MACOSX_CORE__)\r
-  if ( api == MACOSX_CORE )\r
-    rtapi_ = new RtApiCore();\r
-#endif\r
-#if defined(__RTAUDIO_DUMMY__)\r
-  if ( api == RTAUDIO_DUMMY )\r
-    rtapi_ = new RtApiDummy();\r
-#endif\r
-}\r
-\r
-RtAudio :: RtAudio( RtAudio::Api api )\r
-{\r
-  rtapi_ = 0;\r
-\r
-  if ( api != UNSPECIFIED ) {\r
-    // Attempt to open the specified API.\r
-    openRtApi( api );\r
-    if ( rtapi_ ) return;\r
-\r
-    // No compiled support for specified API value.  Issue a debug\r
-    // warning and continue as if no API was specified.\r
-    std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;\r
-  }\r
-\r
-  // Iterate through the compiled APIs and return as soon as we find\r
-  // one with at least one device or we reach the end of the list.\r
-  std::vector< RtAudio::Api > apis;\r
-  getCompiledApi( apis );\r
-  for ( unsigned int i=0; i<apis.size(); i++ ) {\r
-    openRtApi( apis[i] );\r
-    if ( rtapi_->getDeviceCount() ) break;\r
-  }\r
-\r
-  if ( rtapi_ ) return;\r
-\r
-  // It should not be possible to get here because the preprocessor\r
-  // definition __RTAUDIO_DUMMY__ is automatically defined if no\r
-  // API-specific definitions are passed to the compiler. But just in\r
-  // case something weird happens, we'll thow an error.\r
-  std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";\r
-  throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );\r
-}\r
-\r
-RtAudio :: ~RtAudio() throw()\r
-{\r
-  if ( rtapi_ )\r
-    delete rtapi_;\r
-}\r
-\r
-void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,\r
-                            RtAudio::StreamParameters *inputParameters,\r
-                            RtAudioFormat format, unsigned int sampleRate,\r
-                            unsigned int *bufferFrames,\r
-                            RtAudioCallback callback, void *userData,\r
-                            RtAudio::StreamOptions *options,\r
-                            RtAudioErrorCallback errorCallback )\r
-{\r
-  return rtapi_->openStream( outputParameters, inputParameters, format,\r
-                             sampleRate, bufferFrames, callback,\r
-                             userData, options, errorCallback );\r
-}\r
-\r
-// *************************************************** //\r
-//\r
-// Public RtApi definitions (see end of file for\r
-// private or protected utility functions).\r
-//\r
-// *************************************************** //\r
-\r
-RtApi :: RtApi()\r
-{\r
-  stream_.state = STREAM_CLOSED;\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.apiHandle = 0;\r
-  stream_.userBuffer[0] = 0;\r
-  stream_.userBuffer[1] = 0;\r
-  MUTEX_INITIALIZE( &stream_.mutex );\r
-  showWarnings_ = true;\r
-  firstErrorOccurred_ = false;\r
-}\r
-\r
-RtApi :: ~RtApi()\r
-{\r
-  MUTEX_DESTROY( &stream_.mutex );\r
-}\r
-\r
-void RtApi :: openStream( RtAudio::StreamParameters *oParams,\r
-                          RtAudio::StreamParameters *iParams,\r
-                          RtAudioFormat format, unsigned int sampleRate,\r
-                          unsigned int *bufferFrames,\r
-                          RtAudioCallback callback, void *userData,\r
-                          RtAudio::StreamOptions *options,\r
-                          RtAudioErrorCallback errorCallback )\r
-{\r
-  if ( stream_.state != STREAM_CLOSED ) {\r
-    errorText_ = "RtApi::openStream: a stream is already open!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-\r
-  // Clear stream information potentially left from a previously open stream.\r
-  clearStreamInfo();\r
-\r
-  if ( oParams && oParams->nChannels < 1 ) {\r
-    errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-\r
-  if ( iParams && iParams->nChannels < 1 ) {\r
-    errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-\r
-  if ( oParams == NULL && iParams == NULL ) {\r
-    errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-\r
-  if ( formatBytes(format) == 0 ) {\r
-    errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-\r
-  unsigned int nDevices = getDeviceCount();\r
-  unsigned int oChannels = 0;\r
-  if ( oParams ) {\r
-    oChannels = oParams->nChannels;\r
-    if ( oParams->deviceId >= nDevices ) {\r
-      errorText_ = "RtApi::openStream: output device parameter value is invalid.";\r
-      error( RtAudioError::INVALID_USE );\r
-      return;\r
-    }\r
-  }\r
-\r
-  unsigned int iChannels = 0;\r
-  if ( iParams ) {\r
-    iChannels = iParams->nChannels;\r
-    if ( iParams->deviceId >= nDevices ) {\r
-      errorText_ = "RtApi::openStream: input device parameter value is invalid.";\r
-      error( RtAudioError::INVALID_USE );\r
-      return;\r
-    }\r
-  }\r
-\r
-  bool result;\r
-\r
-  if ( oChannels > 0 ) {\r
-\r
-    result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,\r
-                              sampleRate, format, bufferFrames, options );\r
-    if ( result == false ) {\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  if ( iChannels > 0 ) {\r
-\r
-    result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,\r
-                              sampleRate, format, bufferFrames, options );\r
-    if ( result == false ) {\r
-      if ( oChannels > 0 ) closeStream();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  stream_.callbackInfo.callback = (void *) callback;\r
-  stream_.callbackInfo.userData = userData;\r
-  stream_.callbackInfo.errorCallback = (void *) errorCallback;\r
-\r
-  if ( options ) options->numberOfBuffers = stream_.nBuffers;\r
-  stream_.state = STREAM_STOPPED;\r
-}\r
-\r
-unsigned int RtApi :: getDefaultInputDevice( void )\r
-{\r
-  // Should be implemented in subclasses if possible.\r
-  return 0;\r
-}\r
-\r
-unsigned int RtApi :: getDefaultOutputDevice( void )\r
-{\r
-  // Should be implemented in subclasses if possible.\r
-  return 0;\r
-}\r
-\r
-void RtApi :: closeStream( void )\r
-{\r
-  // MUST be implemented in subclasses!\r
-  return;\r
-}\r
-\r
-bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,\r
-                               unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,\r
-                               RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,\r
-                               RtAudio::StreamOptions * /*options*/ )\r
-{\r
-  // MUST be implemented in subclasses!\r
-  return FAILURE;\r
-}\r
-\r
-void RtApi :: tickStreamTime( void )\r
-{\r
-  // Subclasses that do not provide their own implementation of\r
-  // getStreamTime should call this function once per buffer I/O to\r
-  // provide basic stream time support.\r
-\r
-  stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate );\r
-\r
-#if defined( HAVE_GETTIMEOFDAY )\r
-  gettimeofday( &stream_.lastTickTimestamp, NULL );\r
-#endif\r
-}\r
-\r
-long RtApi :: getStreamLatency( void )\r
-{\r
-  verifyStream();\r
-\r
-  long totalLatency = 0;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
-    totalLatency = stream_.latency[0];\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX )\r
-    totalLatency += stream_.latency[1];\r
-\r
-  return totalLatency;\r
-}\r
-\r
-double RtApi :: getStreamTime( void )\r
-{\r
-  verifyStream();\r
-\r
-#if defined( HAVE_GETTIMEOFDAY )\r
-  // Return a very accurate estimate of the stream time by\r
-  // adding in the elapsed time since the last tick.\r
-  struct timeval then;\r
-  struct timeval now;\r
-\r
-  if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 )\r
-    return stream_.streamTime;\r
-\r
-  gettimeofday( &now, NULL );\r
-  then = stream_.lastTickTimestamp;\r
-  return stream_.streamTime +\r
-    ((now.tv_sec + 0.000001 * now.tv_usec) -\r
-     (then.tv_sec + 0.000001 * then.tv_usec));     \r
-#else\r
-  return stream_.streamTime;\r
-#endif\r
-}\r
-\r
-void RtApi :: setStreamTime( double time )\r
-{\r
-  verifyStream();\r
-\r
-  if ( time >= 0.0 )\r
-    stream_.streamTime = time;\r
-}\r
-\r
-unsigned int RtApi :: getStreamSampleRate( void )\r
-{\r
- verifyStream();\r
-\r
- return stream_.sampleRate;\r
-}\r
-\r
-\r
-// *************************************************** //\r
-//\r
-// OS/API-specific methods.\r
-//\r
-// *************************************************** //\r
-\r
-#if defined(__MACOSX_CORE__)\r
-\r
-// The OS X CoreAudio API is designed to use a separate callback\r
-// procedure for each of its audio devices.  A single RtAudio duplex\r
-// stream using two different devices is supported here, though it\r
-// cannot be guaranteed to always behave correctly because we cannot\r
-// synchronize these two callbacks.\r
-//\r
-// A property listener is installed for over/underrun information.\r
-// However, no functionality is currently provided to allow property\r
-// listeners to trigger user handlers because it is unclear what could\r
-// be done if a critical stream parameter (buffer size, sample rate,\r
-// device disconnect) notification arrived.  The listeners entail\r
-// quite a bit of extra code and most likely, a user program wouldn't\r
-// be prepared for the result anyway.  However, we do provide a flag\r
-// to the client callback function to inform of an over/underrun.\r
-\r
-// A structure to hold various information related to the CoreAudio API\r
-// implementation.\r
-struct CoreHandle {\r
-  AudioDeviceID id[2];    // device ids\r
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
-  AudioDeviceIOProcID procId[2];\r
-#endif\r
-  UInt32 iStream[2];      // device stream index (or first if using multiple)\r
-  UInt32 nStreams[2];     // number of streams to use\r
-  bool xrun[2];\r
-  char *deviceBuffer;\r
-  pthread_cond_t condition;\r
-  int drainCounter;       // Tracks callback counts when draining\r
-  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
-\r
-  CoreHandle()\r
-    :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
-};\r
-\r
-RtApiCore:: RtApiCore()\r
-{\r
-#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
-  // This is a largely undocumented but absolutely necessary\r
-  // requirement starting with OS-X 10.6.  If not called, queries and\r
-  // updates to various audio device properties are not handled\r
-  // correctly.\r
-  CFRunLoopRef theRunLoop = NULL;\r
-  AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,\r
-                                          kAudioObjectPropertyScopeGlobal,\r
-                                          kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";\r
-    error( RtAudioError::WARNING );\r
-  }\r
-#endif\r
-}\r
-\r
-RtApiCore :: ~RtApiCore()\r
-{\r
-  // The subclass destructor gets called before the base class\r
-  // destructor, so close an existing stream before deallocating\r
-  // apiDeviceId memory.\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-}\r
-\r
-unsigned int RtApiCore :: getDeviceCount( void )\r
-{\r
-  // Find out how many audio devices there are, if any.\r
-  UInt32 dataSize;\r
-  AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  return dataSize / sizeof( AudioDeviceID );\r
-}\r
-\r
-unsigned int RtApiCore :: getDefaultInputDevice( void )\r
-{\r
-  unsigned int nDevices = getDeviceCount();\r
-  if ( nDevices <= 1 ) return 0;\r
-\r
-  AudioDeviceID id;\r
-  UInt32 dataSize = sizeof( AudioDeviceID );\r
-  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  dataSize *= nDevices;\r
-  AudioDeviceID deviceList[ nDevices ];\r
-  property.mSelector = kAudioHardwarePropertyDevices;\r
-  result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  for ( unsigned int i=0; i<nDevices; i++ )\r
-    if ( id == deviceList[i] ) return i;\r
-\r
-  errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";\r
-  error( RtAudioError::WARNING );\r
-  return 0;\r
-}\r
-\r
-unsigned int RtApiCore :: getDefaultOutputDevice( void )\r
-{\r
-  unsigned int nDevices = getDeviceCount();\r
-  if ( nDevices <= 1 ) return 0;\r
-\r
-  AudioDeviceID id;\r
-  UInt32 dataSize = sizeof( AudioDeviceID );\r
-  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  dataSize = sizeof( AudioDeviceID ) * nDevices;\r
-  AudioDeviceID deviceList[ nDevices ];\r
-  property.mSelector = kAudioHardwarePropertyDevices;\r
-  result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  for ( unsigned int i=0; i<nDevices; i++ )\r
-    if ( id == deviceList[i] ) return i;\r
-\r
-  errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";\r
-  error( RtAudioError::WARNING );\r
-  return 0;\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  // Get device ID\r
-  unsigned int nDevices = getDeviceCount();\r
-  if ( nDevices == 0 ) {\r
-    errorText_ = "RtApiCore::getDeviceInfo: no devices found!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  AudioDeviceID deviceList[ nDevices ];\r
-  UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;\r
-  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,\r
-                                          kAudioObjectPropertyScopeGlobal,\r
-                                          kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,\r
-                                                0, NULL, &dataSize, (void *) &deviceList );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  AudioDeviceID id = deviceList[ device ];\r
-\r
-  // Get the device name.\r
-  info.name.erase();\r
-  CFStringRef cfname;\r
-  dataSize = sizeof( CFStringRef );\r
-  property.mSelector = kAudioObjectPropertyManufacturer;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );\r
-  int length = CFStringGetLength(cfname);\r
-  char *mname = (char *)malloc(length * 3 + 1);\r
-#if defined( UNICODE ) || defined( _UNICODE )\r
-  CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8);\r
-#else\r
-  CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());\r
-#endif\r
-  info.name.append( (const char *)mname, strlen(mname) );\r
-  info.name.append( ": " );\r
-  CFRelease( cfname );\r
-  free(mname);\r
-\r
-  property.mSelector = kAudioObjectPropertyName;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );\r
-  length = CFStringGetLength(cfname);\r
-  char *name = (char *)malloc(length * 3 + 1);\r
-#if defined( UNICODE ) || defined( _UNICODE )\r
-  CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8);\r
-#else\r
-  CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());\r
-#endif\r
-  info.name.append( (const char *)name, strlen(name) );\r
-  CFRelease( cfname );\r
-  free(name);\r
-\r
-  // Get the output stream "configuration".\r
-  AudioBufferList      *bufferList = nil;\r
-  property.mSelector = kAudioDevicePropertyStreamConfiguration;\r
-  property.mScope = kAudioDevicePropertyScopeOutput;\r
-  //  property.mElement = kAudioObjectPropertyElementWildcard;\r
-  dataSize = 0;\r
-  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
-  if ( result != noErr || dataSize == 0 ) {\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Allocate the AudioBufferList.\r
-  bufferList = (AudioBufferList *) malloc( dataSize );\r
-  if ( bufferList == NULL ) {\r
-    errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
-  if ( result != noErr || dataSize == 0 ) {\r
-    free( bufferList );\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Get output channel information.\r
-  unsigned int i, nStreams = bufferList->mNumberBuffers;\r
-  for ( i=0; i<nStreams; i++ )\r
-    info.outputChannels += bufferList->mBuffers[i].mNumberChannels;\r
-  free( bufferList );\r
-\r
-  // Get the input stream "configuration".\r
-  property.mScope = kAudioDevicePropertyScopeInput;\r
-  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
-  if ( result != noErr || dataSize == 0 ) {\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Allocate the AudioBufferList.\r
-  bufferList = (AudioBufferList *) malloc( dataSize );\r
-  if ( bufferList == NULL ) {\r
-    errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
-  if (result != noErr || dataSize == 0) {\r
-    free( bufferList );\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Get input channel information.\r
-  nStreams = bufferList->mNumberBuffers;\r
-  for ( i=0; i<nStreams; i++ )\r
-    info.inputChannels += bufferList->mBuffers[i].mNumberChannels;\r
-  free( bufferList );\r
-\r
-  // If device opens for both playback and capture, we determine the channels.\r
-  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
-    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-\r
-  // Probe the device sample rates.\r
-  bool isInput = false;\r
-  if ( info.outputChannels == 0 ) isInput = true;\r
-\r
-  // Determine the supported sample rates.\r
-  property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;\r
-  if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput;\r
-  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
-  if ( result != kAudioHardwareNoError || dataSize == 0 ) {\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  UInt32 nRanges = dataSize / sizeof( AudioValueRange );\r
-  AudioValueRange rangeList[ nRanges ];\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList );\r
-  if ( result != kAudioHardwareNoError ) {\r
-    errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // The sample rate reporting mechanism is a bit of a mystery.  It\r
-  // seems that it can either return individual rates or a range of\r
-  // rates.  I assume that if the min / max range values are the same,\r
-  // then that represents a single supported rate and if the min / max\r
-  // range values are different, the device supports an arbitrary\r
-  // range of values (though there might be multiple ranges, so we'll\r
-  // use the most conservative range).\r
-  Float64 minimumRate = 1.0, maximumRate = 10000000000.0;\r
-  bool haveValueRange = false;\r
-  info.sampleRates.clear();\r
-  for ( UInt32 i=0; i<nRanges; i++ ) {\r
-    if ( rangeList[i].mMinimum == rangeList[i].mMaximum )\r
-      info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );\r
-    else {\r
-      haveValueRange = true;\r
-      if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;\r
-      if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;\r
-    }\r
-  }\r
-\r
-  if ( haveValueRange ) {\r
-    for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )\r
-        info.sampleRates.push_back( SAMPLE_RATES[k] );\r
-    }\r
-  }\r
-\r
-  // Sort and remove any redundant values\r
-  std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
-  info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );\r
-\r
-  if ( info.sampleRates.size() == 0 ) {\r
-    errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // CoreAudio always uses 32-bit floating point data for PCM streams.\r
-  // Thus, any other "physical" formats supported by the device are of\r
-  // no interest to the client.\r
-  info.nativeFormats = RTAUDIO_FLOAT32;\r
-\r
-  if ( info.outputChannels > 0 )\r
-    if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;\r
-  if ( info.inputChannels > 0 )\r
-    if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;\r
-\r
-  info.probed = true;\r
-  return info;\r
-}\r
-\r
-static OSStatus callbackHandler( AudioDeviceID inDevice,\r
-                                 const AudioTimeStamp* /*inNow*/,\r
-                                 const AudioBufferList* inInputData,\r
-                                 const AudioTimeStamp* /*inInputTime*/,\r
-                                 AudioBufferList* outOutputData,\r
-                                 const AudioTimeStamp* /*inOutputTime*/,\r
-                                 void* infoPointer )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
-\r
-  RtApiCore *object = (RtApiCore *) info->object;\r
-  if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )\r
-    return kAudioHardwareUnspecifiedError;\r
-  else\r
-    return kAudioHardwareNoError;\r
-}\r
-\r
-static OSStatus xrunListener( AudioObjectID /*inDevice*/,\r
-                              UInt32 nAddresses,\r
-                              const AudioObjectPropertyAddress properties[],\r
-                              void* handlePointer )\r
-{\r
-  CoreHandle *handle = (CoreHandle *) handlePointer;\r
-  for ( UInt32 i=0; i<nAddresses; i++ ) {\r
-    if ( properties[i].mSelector == kAudioDeviceProcessorOverload ) {\r
-      if ( properties[i].mScope == kAudioDevicePropertyScopeInput )\r
-        handle->xrun[1] = true;\r
-      else\r
-        handle->xrun[0] = true;\r
-    }\r
-  }\r
-\r
-  return kAudioHardwareNoError;\r
-}\r
-\r
-static OSStatus rateListener( AudioObjectID inDevice,\r
-                              UInt32 /*nAddresses*/,\r
-                              const AudioObjectPropertyAddress /*properties*/[],\r
-                              void* ratePointer )\r
-{\r
-  Float64 *rate = (Float64 *) ratePointer;\r
-  UInt32 dataSize = sizeof( Float64 );\r
-  AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,\r
-                                          kAudioObjectPropertyScopeGlobal,\r
-                                          kAudioObjectPropertyElementMaster };\r
-  AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );\r
-  return kAudioHardwareNoError;\r
-}\r
-\r
-bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                   unsigned int firstChannel, unsigned int sampleRate,\r
-                                   RtAudioFormat format, unsigned int *bufferSize,\r
-                                   RtAudio::StreamOptions *options )\r
-{\r
-  // Get device ID\r
-  unsigned int nDevices = getDeviceCount();\r
-  if ( nDevices == 0 ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    errorText_ = "RtApiCore::probeDeviceOpen: no devices found!";\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!";\r
-    return FAILURE;\r
-  }\r
-\r
-  AudioDeviceID deviceList[ nDevices ];\r
-  UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;\r
-  AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,\r
-                                          kAudioObjectPropertyScopeGlobal,\r
-                                          kAudioObjectPropertyElementMaster };\r
-  OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,\r
-                                                0, NULL, &dataSize, (void *) &deviceList );\r
-  if ( result != noErr ) {\r
-    errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs.";\r
-    return FAILURE;\r
-  }\r
-\r
-  AudioDeviceID id = deviceList[ device ];\r
-\r
-  // Setup for stream mode.\r
-  bool isInput = false;\r
-  if ( mode == INPUT ) {\r
-    isInput = true;\r
-    property.mScope = kAudioDevicePropertyScopeInput;\r
-  }\r
-  else\r
-    property.mScope = kAudioDevicePropertyScopeOutput;\r
-\r
-  // Get the stream "configuration".\r
-  AudioBufferList      *bufferList = nil;\r
-  dataSize = 0;\r
-  property.mSelector = kAudioDevicePropertyStreamConfiguration;\r
-  result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );\r
-  if ( result != noErr || dataSize == 0 ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Allocate the AudioBufferList.\r
-  bufferList = (AudioBufferList *) malloc( dataSize );\r
-  if ( bufferList == NULL ) {\r
-    errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList.";\r
-    return FAILURE;\r
-  }\r
-\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
-  if (result != noErr || dataSize == 0) {\r
-    free( bufferList );\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Search for one or more streams that contain the desired number of\r
-  // channels. CoreAudio devices can have an arbitrary number of\r
-  // streams and each stream can have an arbitrary number of channels.\r
-  // For each stream, a single buffer of interleaved samples is\r
-  // provided.  RtAudio prefers the use of one stream of interleaved\r
-  // data or multiple consecutive single-channel streams.  However, we\r
-  // now support multiple consecutive multi-channel streams of\r
-  // interleaved data as well.\r
-  UInt32 iStream, offsetCounter = firstChannel;\r
-  UInt32 nStreams = bufferList->mNumberBuffers;\r
-  bool monoMode = false;\r
-  bool foundStream = false;\r
-\r
-  // First check that the device supports the requested number of\r
-  // channels.\r
-  UInt32 deviceChannels = 0;\r
-  for ( iStream=0; iStream<nStreams; iStream++ )\r
-    deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;\r
-\r
-  if ( deviceChannels < ( channels + firstChannel ) ) {\r
-    free( bufferList );\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Look for a single stream meeting our needs.\r
-  UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;\r
-  for ( iStream=0; iStream<nStreams; iStream++ ) {\r
-    streamChannels = bufferList->mBuffers[iStream].mNumberChannels;\r
-    if ( streamChannels >= channels + offsetCounter ) {\r
-      firstStream = iStream;\r
-      channelOffset = offsetCounter;\r
-      foundStream = true;\r
-      break;\r
-    }\r
-    if ( streamChannels > offsetCounter ) break;\r
-    offsetCounter -= streamChannels;\r
-  }\r
-\r
-  // If we didn't find a single stream above, then we should be able\r
-  // to meet the channel specification with multiple streams.\r
-  if ( foundStream == false ) {\r
-    monoMode = true;\r
-    offsetCounter = firstChannel;\r
-    for ( iStream=0; iStream<nStreams; iStream++ ) {\r
-      streamChannels = bufferList->mBuffers[iStream].mNumberChannels;\r
-      if ( streamChannels > offsetCounter ) break;\r
-      offsetCounter -= streamChannels;\r
-    }\r
-\r
-    firstStream = iStream;\r
-    channelOffset = offsetCounter;\r
-    Int32 channelCounter = channels + offsetCounter - streamChannels;\r
-\r
-    if ( streamChannels > 1 ) monoMode = false;\r
-    while ( channelCounter > 0 ) {\r
-      streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;\r
-      if ( streamChannels > 1 ) monoMode = false;\r
-      channelCounter -= streamChannels;\r
-      streamCount++;\r
-    }\r
-  }\r
-\r
-  free( bufferList );\r
-\r
-  // Determine the buffer size.\r
-  AudioValueRange      bufferRange;\r
-  dataSize = sizeof( AudioValueRange );\r
-  property.mSelector = kAudioDevicePropertyBufferFrameSizeRange;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange );\r
-\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum;\r
-  else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;\r
-  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;\r
-\r
-  // Set the buffer size.  For multiple streams, I'm assuming we only\r
-  // need to make this setting for the master channel.\r
-  UInt32 theSize = (UInt32) *bufferSize;\r
-  dataSize = sizeof( UInt32 );\r
-  property.mSelector = kAudioDevicePropertyBufferFrameSize;\r
-  result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize );\r
-\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // If attempting to setup a duplex stream, the bufferSize parameter\r
-  // MUST be the same in both directions!\r
-  *bufferSize = theSize;\r
-  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  stream_.bufferSize = *bufferSize;\r
-  stream_.nBuffers = 1;\r
-\r
-  // Try to set "hog" mode ... it's not clear to me this is working.\r
-  if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {\r
-    pid_t hog_pid;\r
-    dataSize = sizeof( hog_pid );\r
-    property.mSelector = kAudioDevicePropertyHogMode;\r
-    result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    if ( hog_pid != getpid() ) {\r
-      hog_pid = getpid();\r
-      result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid );\r
-      if ( result != noErr ) {\r
-        errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";\r
-        errorText_ = errorStream_.str();\r
-        return FAILURE;\r
-      }\r
-    }\r
-  }\r
-\r
-  // Check and if necessary, change the sample rate for the device.\r
-  Float64 nominalRate;\r
-  dataSize = sizeof( Float64 );\r
-  property.mSelector = kAudioDevicePropertyNominalSampleRate;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Only change the sample rate if off by more than 1 Hz.\r
-  if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {\r
-\r
-    // Set a property listener for the sample rate change\r
-    Float64 reportedRate = 0.0;\r
-    AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
-    result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    nominalRate = (Float64) sampleRate;\r
-    result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );\r
-    if ( result != noErr ) {\r
-      AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Now wait until the reported nominal rate is what we just set.\r
-    UInt32 microCounter = 0;\r
-    while ( reportedRate != nominalRate ) {\r
-      microCounter += 5000;\r
-      if ( microCounter > 5000000 ) break;\r
-      usleep( 5000 );\r
-    }\r
-\r
-    // Remove the property listener.\r
-    AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
-\r
-    if ( microCounter > 5000000 ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // Now set the stream format for all streams.  Also, check the\r
-  // physical format of the device and change that if necessary.\r
-  AudioStreamBasicDescription  description;\r
-  dataSize = sizeof( AudioStreamBasicDescription );\r
-  property.mSelector = kAudioStreamPropertyVirtualFormat;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the sample rate and data format id.  However, only make the\r
-  // change if the sample rate is not within 1.0 of the desired\r
-  // rate and the format is not linear pcm.\r
-  bool updateFormat = false;\r
-  if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {\r
-    description.mSampleRate = (Float64) sampleRate;\r
-    updateFormat = true;\r
-  }\r
-\r
-  if ( description.mFormatID != kAudioFormatLinearPCM ) {\r
-    description.mFormatID = kAudioFormatLinearPCM;\r
-    updateFormat = true;\r
-  }\r
-\r
-  if ( updateFormat ) {\r
-    result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // Now check the physical format.\r
-  property.mSelector = kAudioStreamPropertyPhysicalFormat;\r
-  result = AudioObjectGetPropertyData( id, &property, 0, NULL,  &dataSize, &description );\r
-  if ( result != noErr ) {\r
-    errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  //std::cout << "Current physical stream format:" << std::endl;\r
-  //std::cout << "   mBitsPerChan = " << description.mBitsPerChannel << std::endl;\r
-  //std::cout << "   aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
-  //std::cout << "   bytesPerFrame = " << description.mBytesPerFrame << std::endl;\r
-  //std::cout << "   sample rate = " << description.mSampleRate << std::endl;\r
-\r
-  if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {\r
-    description.mFormatID = kAudioFormatLinearPCM;\r
-    //description.mSampleRate = (Float64) sampleRate;\r
-    AudioStreamBasicDescription        testDescription = description;\r
-    UInt32 formatFlags;\r
-\r
-    // We'll try higher bit rates first and then work our way down.\r
-    std::vector< std::pair<UInt32, UInt32>  > physicalFormats;\r
-    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger;\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
-    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) );   // 24-bit packed\r
-    formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low\r
-    formatFlags |= kAudioFormatFlagIsAlignedHigh;\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high\r
-    formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );\r
-    physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );\r
-\r
-    bool setPhysicalFormat = false;\r
-    for( unsigned int i=0; i<physicalFormats.size(); i++ ) {\r
-      testDescription = description;\r
-      testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;\r
-      testDescription.mFormatFlags = physicalFormats[i].second;\r
-      if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )\r
-        testDescription.mBytesPerFrame =  4 * testDescription.mChannelsPerFrame;\r
-      else\r
-        testDescription.mBytesPerFrame =  testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
-      testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
-      result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );\r
-      if ( result == noErr ) {\r
-        setPhysicalFormat = true;\r
-        //std::cout << "Updated physical stream format:" << std::endl;\r
-        //std::cout << "   mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;\r
-        //std::cout << "   aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
-        //std::cout << "   bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;\r
-        //std::cout << "   sample rate = " << testDescription.mSampleRate << std::endl;\r
-        break;\r
-      }\r
-    }\r
-\r
-    if ( !setPhysicalFormat ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  } // done setting virtual/physical formats.\r
-\r
-  // Get the stream / device latency.\r
-  UInt32 latency;\r
-  dataSize = sizeof( UInt32 );\r
-  property.mSelector = kAudioDevicePropertyLatency;\r
-  if ( AudioObjectHasProperty( id, &property ) == true ) {\r
-    result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &latency );\r
-    if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;\r
-    else {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::WARNING );\r
-    }\r
-  }\r
-\r
-  // Byte-swapping: According to AudioHardware.h, the stream data will\r
-  // always be presented in native-endian format, so we should never\r
-  // need to byte swap.\r
-  stream_.doByteSwap[mode] = false;\r
-\r
-  // From the CoreAudio documentation, PCM data must be supplied as\r
-  // 32-bit floats.\r
-  stream_.userFormat = format;\r
-  stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
-\r
-  if ( streamCount == 1 )\r
-    stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;\r
-  else // multiple streams\r
-    stream_.nDeviceChannels[mode] = channels;\r
-  stream_.nUserChannels[mode] = channels;\r
-  stream_.channelOffset[mode] = channelOffset;  // offset within a CoreAudio stream\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
-  else stream_.userInterleaved = true;\r
-  stream_.deviceInterleaved[mode] = true;\r
-  if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;\r
-\r
-  // Set flags for buffer conversion.\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( streamCount == 1 ) {\r
-    if ( stream_.nUserChannels[mode] > 1 &&\r
-         stream_.userInterleaved != stream_.deviceInterleaved[mode] )\r
-      stream_.doConvertBuffer[mode] = true;\r
-  }\r
-  else if ( monoMode && stream_.userInterleaved )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate our CoreHandle structure for the stream.\r
-  CoreHandle *handle = 0;\r
-  if ( stream_.apiHandle == 0 ) {\r
-    try {\r
-      handle = new CoreHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory.";\r
-      goto error;\r
-    }\r
-\r
-    if ( pthread_cond_init( &handle->condition, NULL ) ) {\r
-      errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable.";\r
-      goto error;\r
-    }\r
-    stream_.apiHandle = (void *) handle;\r
-  }\r
-  else\r
-    handle = (CoreHandle *) stream_.apiHandle;\r
-  handle->iStream[mode] = firstStream;\r
-  handle->nStreams[mode] = streamCount;\r
-  handle->id[mode] = id;\r
-\r
-  // Allocate necessary internal buffers.\r
-  unsigned long bufferBytes;\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  //  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );\r
-  memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  // If possible, we will make use of the CoreAudio stream buffers as\r
-  // "device buffers".  However, we can't do this if using multiple\r
-  // streams.\r
-  if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.sampleRate = sampleRate;\r
-  stream_.device[mode] = device;\r
-  stream_.state = STREAM_STOPPED;\r
-  stream_.callbackInfo.object = (void *) this;\r
-\r
-  // Setup the buffer conversion information structure.\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-    if ( streamCount > 1 ) setConvertInfo( mode, 0 );\r
-    else setConvertInfo( mode, channelOffset );\r
-  }\r
-\r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )\r
-    // Only one callback procedure per device.\r
-    stream_.mode = DUPLEX;\r
-  else {\r
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
-    result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );\r
-#else\r
-    // deprecated in favor of AudioDeviceCreateIOProcID()\r
-    result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );\r
-#endif\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto error;\r
-    }\r
-    if ( stream_.mode == OUTPUT && mode == INPUT )\r
-      stream_.mode = DUPLEX;\r
-    else\r
-      stream_.mode = mode;\r
-  }\r
-\r
-  // Setup the device property listener for over/underload.\r
-  property.mSelector = kAudioDeviceProcessorOverload;\r
-  property.mScope = kAudioObjectPropertyScopeGlobal;\r
-  result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );\r
-\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( handle ) {\r
-    pthread_cond_destroy( &handle->condition );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.state = STREAM_CLOSED;\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiCore :: closeStream( void )\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiCore::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    if ( stream_.state == STREAM_RUNNING )\r
-      AudioDeviceStop( handle->id[0], callbackHandler );\r
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
-    AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );\r
-#else\r
-    // deprecated in favor of AudioDeviceDestroyIOProcID()\r
-    AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );\r
-#endif\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
-    if ( stream_.state == STREAM_RUNNING )\r
-      AudioDeviceStop( handle->id[1], callbackHandler );\r
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )\r
-    AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );\r
-#else\r
-    // deprecated in favor of AudioDeviceDestroyIOProcID()\r
-    AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );\r
-#endif\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  // Destroy pthread condition variable.\r
-  pthread_cond_destroy( &handle->condition );\r
-  delete handle;\r
-  stream_.apiHandle = 0;\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-void RtApiCore :: startStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiCore::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  OSStatus result = noErr;\r
-  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    result = AudioDeviceStart( handle->id[0], callbackHandler );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT ||\r
-       ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
-\r
-    result = AudioDeviceStart( handle->id[1], callbackHandler );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  handle->drainCounter = 0;\r
-  handle->internalDrain = false;\r
-  stream_.state = STREAM_RUNNING;\r
-\r
- unlock:\r
-  if ( result == noErr ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiCore :: stopStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  OSStatus result = noErr;\r
-  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    if ( handle->drainCounter == 0 ) {\r
-      handle->drainCounter = 2;\r
-      pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled\r
-    }\r
-\r
-    result = AudioDeviceStop( handle->id[0], callbackHandler );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
-\r
-    result = AudioDeviceStop( handle->id[1], callbackHandler );\r
-    if ( result != noErr ) {\r
-      errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-\r
- unlock:\r
-  if ( result == noErr ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiCore :: abortStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
-  handle->drainCounter = 2;\r
-\r
-  stopStream();\r
-}\r
-\r
-// This function will be called by a spawned thread when the user\r
-// callback function signals that the stream should be stopped or\r
-// aborted.  It is better to handle it this way because the\r
-// callbackEvent() function probably should return before the AudioDeviceStop()\r
-// function is called.\r
-static void *coreStopStream( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiCore *object = (RtApiCore *) info->object;\r
-\r
-  object->stopStream();\r
-  pthread_exit( NULL );\r
-}\r
-\r
-bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,\r
-                                 const AudioBufferList *inBufferList,\r
-                                 const AudioBufferList *outBufferList )\r
-{\r
-  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return FAILURE;\r
-  }\r
-\r
-  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
-  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
-\r
-  // Check if we were draining the stream and signal is finished.\r
-  if ( handle->drainCounter > 3 ) {\r
-    ThreadHandle threadId;\r
-\r
-    stream_.state = STREAM_STOPPING;\r
-    if ( handle->internalDrain == true )\r
-      pthread_create( &threadId, NULL, coreStopStream, info );\r
-    else // external call to stopStream()\r
-      pthread_cond_signal( &handle->condition );\r
-    return SUCCESS;\r
-  }\r
-\r
-  AudioDeviceID outputDevice = handle->id[0];\r
-\r
-  // Invoke user callback to get fresh output data UNLESS we are\r
-  // draining stream or duplex mode AND the input/output devices are\r
-  // different AND this function is called for the input device.\r
-  if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) {\r
-    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
-    double streamTime = getStreamTime();\r
-    RtAudioStreamStatus status = 0;\r
-    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
-      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-      handle->xrun[0] = false;\r
-    }\r
-    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
-      status |= RTAUDIO_INPUT_OVERFLOW;\r
-      handle->xrun[1] = false;\r
-    }\r
-\r
-    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                                  stream_.bufferSize, streamTime, status, info->userData );\r
-    if ( cbReturnValue == 2 ) {\r
-      stream_.state = STREAM_STOPPING;\r
-      handle->drainCounter = 2;\r
-      abortStream();\r
-      return SUCCESS;\r
-    }\r
-    else if ( cbReturnValue == 1 ) {\r
-      handle->drainCounter = 1;\r
-      handle->internalDrain = true;\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {\r
-\r
-    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
-\r
-      if ( handle->nStreams[0] == 1 ) {\r
-        memset( outBufferList->mBuffers[handle->iStream[0]].mData,\r
-                0,\r
-                outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );\r
-      }\r
-      else { // fill multiple streams with zeros\r
-        for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {\r
-          memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,\r
-                  0,\r
-                  outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );\r
-        }\r
-      }\r
-    }\r
-    else if ( handle->nStreams[0] == 1 ) {\r
-      if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer\r
-        convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,\r
-                       stream_.userBuffer[0], stream_.convertInfo[0] );\r
-      }\r
-      else { // copy from user buffer\r
-        memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,\r
-                stream_.userBuffer[0],\r
-                outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );\r
-      }\r
-    }\r
-    else { // fill multiple streams\r
-      Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];\r
-      if ( stream_.doConvertBuffer[0] ) {\r
-        convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-        inBuffer = (Float32 *) stream_.deviceBuffer;\r
-      }\r
-\r
-      if ( stream_.deviceInterleaved[0] == false ) { // mono mode\r
-        UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;\r
-        for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
-          memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,\r
-                  (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );\r
-        }\r
-      }\r
-      else { // fill multiple multi-channel streams with interleaved data\r
-        UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;\r
-        Float32 *out, *in;\r
-\r
-        bool inInterleaved = ( stream_.userInterleaved ) ? true : false;\r
-        UInt32 inChannels = stream_.nUserChannels[0];\r
-        if ( stream_.doConvertBuffer[0] ) {\r
-          inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode\r
-          inChannels = stream_.nDeviceChannels[0];\r
-        }\r
-\r
-        if ( inInterleaved ) inOffset = 1;\r
-        else inOffset = stream_.bufferSize;\r
-\r
-        channelsLeft = inChannels;\r
-        for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {\r
-          in = inBuffer;\r
-          out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;\r
-          streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;\r
-\r
-          outJump = 0;\r
-          // Account for possible channel offset in first stream\r
-          if ( i == 0 && stream_.channelOffset[0] > 0 ) {\r
-            streamChannels -= stream_.channelOffset[0];\r
-            outJump = stream_.channelOffset[0];\r
-            out += outJump;\r
-          }\r
-\r
-          // Account for possible unfilled channels at end of the last stream\r
-          if ( streamChannels > channelsLeft ) {\r
-            outJump = streamChannels - channelsLeft;\r
-            streamChannels = channelsLeft;\r
-          }\r
-\r
-          // Determine input buffer offsets and skips\r
-          if ( inInterleaved ) {\r
-            inJump = inChannels;\r
-            in += inChannels - channelsLeft;\r
-          }\r
-          else {\r
-            inJump = 1;\r
-            in += (inChannels - channelsLeft) * inOffset;\r
-          }\r
-\r
-          for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {\r
-            for ( unsigned int j=0; j<streamChannels; j++ ) {\r
-              *out++ = in[j*inOffset];\r
-            }\r
-            out += outJump;\r
-            in += inJump;\r
-          }\r
-          channelsLeft -= streamChannels;\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  // Don't bother draining input\r
-  if ( handle->drainCounter ) {\r
-    handle->drainCounter++;\r
-    goto unlock;\r
-  }\r
-\r
-  AudioDeviceID inputDevice;\r
-  inputDevice = handle->id[1];\r
-  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {\r
-\r
-    if ( handle->nStreams[1] == 1 ) {\r
-      if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer\r
-        convertBuffer( stream_.userBuffer[1],\r
-                       (char *) inBufferList->mBuffers[handle->iStream[1]].mData,\r
-                       stream_.convertInfo[1] );\r
-      }\r
-      else { // copy to user buffer\r
-        memcpy( stream_.userBuffer[1],\r
-                inBufferList->mBuffers[handle->iStream[1]].mData,\r
-                inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );\r
-      }\r
-    }\r
-    else { // read from multiple streams\r
-      Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];\r
-      if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;\r
-\r
-      if ( stream_.deviceInterleaved[1] == false ) { // mono mode\r
-        UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;\r
-        for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
-          memcpy( (void *)&outBuffer[i*stream_.bufferSize],\r
-                  inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );\r
-        }\r
-      }\r
-      else { // read from multiple multi-channel streams\r
-        UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;\r
-        Float32 *out, *in;\r
-\r
-        bool outInterleaved = ( stream_.userInterleaved ) ? true : false;\r
-        UInt32 outChannels = stream_.nUserChannels[1];\r
-        if ( stream_.doConvertBuffer[1] ) {\r
-          outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode\r
-          outChannels = stream_.nDeviceChannels[1];\r
-        }\r
-\r
-        if ( outInterleaved ) outOffset = 1;\r
-        else outOffset = stream_.bufferSize;\r
-\r
-        channelsLeft = outChannels;\r
-        for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {\r
-          out = outBuffer;\r
-          in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;\r
-          streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;\r
-\r
-          inJump = 0;\r
-          // Account for possible channel offset in first stream\r
-          if ( i == 0 && stream_.channelOffset[1] > 0 ) {\r
-            streamChannels -= stream_.channelOffset[1];\r
-            inJump = stream_.channelOffset[1];\r
-            in += inJump;\r
-          }\r
-\r
-          // Account for possible unread channels at end of the last stream\r
-          if ( streamChannels > channelsLeft ) {\r
-            inJump = streamChannels - channelsLeft;\r
-            streamChannels = channelsLeft;\r
-          }\r
-\r
-          // Determine output buffer offsets and skips\r
-          if ( outInterleaved ) {\r
-            outJump = outChannels;\r
-            out += outChannels - channelsLeft;\r
-          }\r
-          else {\r
-            outJump = 1;\r
-            out += (outChannels - channelsLeft) * outOffset;\r
-          }\r
-\r
-          for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {\r
-            for ( unsigned int j=0; j<streamChannels; j++ ) {\r
-              out[j*outOffset] = *in++;\r
-            }\r
-            out += outJump;\r
-            in += inJump;\r
-          }\r
-          channelsLeft -= streamChannels;\r
-        }\r
-      }\r
-      \r
-      if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer\r
-        convertBuffer( stream_.userBuffer[1],\r
-                       stream_.deviceBuffer,\r
-                       stream_.convertInfo[1] );\r
-      }\r
-    }\r
-  }\r
-\r
- unlock:\r
-  //MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  RtApi::tickStreamTime();\r
-  return SUCCESS;\r
-}\r
-\r
-const char* RtApiCore :: getErrorCode( OSStatus code )\r
-{\r
-  switch( code ) {\r
-\r
-  case kAudioHardwareNotRunningError:\r
-    return "kAudioHardwareNotRunningError";\r
-\r
-  case kAudioHardwareUnspecifiedError:\r
-    return "kAudioHardwareUnspecifiedError";\r
-\r
-  case kAudioHardwareUnknownPropertyError:\r
-    return "kAudioHardwareUnknownPropertyError";\r
-\r
-  case kAudioHardwareBadPropertySizeError:\r
-    return "kAudioHardwareBadPropertySizeError";\r
-\r
-  case kAudioHardwareIllegalOperationError:\r
-    return "kAudioHardwareIllegalOperationError";\r
-\r
-  case kAudioHardwareBadObjectError:\r
-    return "kAudioHardwareBadObjectError";\r
-\r
-  case kAudioHardwareBadDeviceError:\r
-    return "kAudioHardwareBadDeviceError";\r
-\r
-  case kAudioHardwareBadStreamError:\r
-    return "kAudioHardwareBadStreamError";\r
-\r
-  case kAudioHardwareUnsupportedOperationError:\r
-    return "kAudioHardwareUnsupportedOperationError";\r
-\r
-  case kAudioDeviceUnsupportedFormatError:\r
-    return "kAudioDeviceUnsupportedFormatError";\r
-\r
-  case kAudioDevicePermissionsError:\r
-    return "kAudioDevicePermissionsError";\r
-\r
-  default:\r
-    return "CoreAudio unknown error";\r
-  }\r
-}\r
-\r
-  //******************** End of __MACOSX_CORE__ *********************//\r
-#endif\r
-\r
-#if defined(__UNIX_JACK__)\r
-\r
-// JACK is a low-latency audio server, originally written for the\r
-// GNU/Linux operating system and now also ported to OS-X. It can\r
-// connect a number of different applications to an audio device, as\r
-// well as allowing them to share audio between themselves.\r
-//\r
-// When using JACK with RtAudio, "devices" refer to JACK clients that\r
-// have ports connected to the server.  The JACK server is typically\r
-// started in a terminal as follows:\r
-//\r
-// .jackd -d alsa -d hw:0\r
-//\r
-// or through an interface program such as qjackctl.  Many of the\r
-// parameters normally set for a stream are fixed by the JACK server\r
-// and can be specified when the JACK server is started.  In\r
-// particular,\r
-//\r
-// .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4\r
-//\r
-// specifies a sample rate of 44100 Hz, a buffer size of 512 sample\r
-// frames, and number of buffers = 4.  Once the server is running, it\r
-// is not possible to override these values.  If the values are not\r
-// specified in the command-line, the JACK server uses default values.\r
-//\r
-// The JACK server does not have to be running when an instance of\r
-// RtApiJack is created, though the function getDeviceCount() will\r
-// report 0 devices found until JACK has been started.  When no\r
-// devices are available (i.e., the JACK server is not running), a\r
-// stream cannot be opened.\r
-\r
-#include <jack/jack.h>\r
-#include <unistd.h>\r
-#include <cstdio>\r
-\r
-// A structure to hold various information related to the Jack API\r
-// implementation.\r
-struct JackHandle {\r
-  jack_client_t *client;\r
-  jack_port_t **ports[2];\r
-  std::string deviceName[2];\r
-  bool xrun[2];\r
-  pthread_cond_t condition;\r
-  int drainCounter;       // Tracks callback counts when draining\r
-  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
-\r
-  JackHandle()\r
-    :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }\r
-};\r
-\r
-/* --- Monocasual hack ---------------------------------------------- */\r
-#ifdef __linux__\r
-void *RtApi :: __HACK__getJackClient() {\r
-       JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-       return (void*) handle->client;\r
-}\r
-#endif\r
-/* ------------------------------------------------------------------ */\r
-\r
-static void jackSilentError( const char * ) {};\r
-\r
-RtApiJack :: RtApiJack()\r
-{\r
-  // Nothing to do here.\r
-#if !defined(__RTAUDIO_DEBUG__)\r
-  // Turn off Jack's internal error reporting.\r
-  jack_set_error_function( &jackSilentError );\r
-#endif\r
-}\r
-\r
-RtApiJack :: ~RtApiJack()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-}\r
-\r
-unsigned int RtApiJack :: getDeviceCount( void )\r
-{\r
-  // See if we can become a jack client.\r
-  jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;\r
-  jack_status_t *status = NULL;\r
-  jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );\r
-  if ( client == 0 ) return 0;\r
-\r
-  const char **ports;\r
-  std::string port, previousPort;\r
-  unsigned int nChannels = 0, nDevices = 0;\r
-  ports = jack_get_ports( client, NULL, NULL, 0 );\r
-  if ( ports ) {\r
-    // Parse the port names up to the first colon (:).\r
-    size_t iColon = 0;\r
-    do {\r
-      port = (char *) ports[ nChannels ];\r
-      iColon = port.find(":");\r
-      if ( iColon != std::string::npos ) {\r
-        port = port.substr( 0, iColon + 1 );\r
-        if ( port != previousPort ) {\r
-          nDevices++;\r
-          previousPort = port;\r
-        }\r
-      }\r
-    } while ( ports[++nChannels] );\r
-    free( ports );\r
-  }\r
-\r
-  jack_client_close( client );\r
-  return nDevices;\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption\r
-  jack_status_t *status = NULL;\r
-  jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );\r
-  if ( client == 0 ) {\r
-    errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  const char **ports;\r
-  std::string port, previousPort;\r
-  unsigned int nPorts = 0, nDevices = 0;\r
-  ports = jack_get_ports( client, NULL, NULL, 0 );\r
-  if ( ports ) {\r
-    // Parse the port names up to the first colon (:).\r
-    size_t iColon = 0;\r
-    do {\r
-      port = (char *) ports[ nPorts ];\r
-      iColon = port.find(":");\r
-      if ( iColon != std::string::npos ) {\r
-        port = port.substr( 0, iColon );\r
-        if ( port != previousPort ) {\r
-          if ( nDevices == device ) info.name = port;\r
-          nDevices++;\r
-          previousPort = port;\r
-        }\r
-      }\r
-    } while ( ports[++nPorts] );\r
-    free( ports );\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    jack_client_close( client );\r
-    errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  // Get the current jack server sample rate.\r
-  info.sampleRates.clear();\r
-  info.sampleRates.push_back( jack_get_sample_rate( client ) );\r
-\r
-  // Count the available ports containing the client name as device\r
-  // channels.  Jack "input ports" equal RtAudio output channels.\r
-  unsigned int nChannels = 0;\r
-  ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );\r
-  if ( ports ) {\r
-    while ( ports[ nChannels ] ) nChannels++;\r
-    free( ports );\r
-    info.outputChannels = nChannels;\r
-  }\r
-\r
-  // Jack "output ports" equal RtAudio input channels.\r
-  nChannels = 0;\r
-  ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );\r
-  if ( ports ) {\r
-    while ( ports[ nChannels ] ) nChannels++;\r
-    free( ports );\r
-    info.inputChannels = nChannels;\r
-  }\r
-\r
-  if ( info.outputChannels == 0 && info.inputChannels == 0 ) {\r
-    jack_client_close(client);\r
-    errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // If device opens for both playback and capture, we determine the channels.\r
-  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
-    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-\r
-  // Jack always uses 32-bit floats.\r
-  info.nativeFormats = RTAUDIO_FLOAT32;\r
-\r
-  // Jack doesn't provide default devices so we'll use the first available one.\r
-  if ( device == 0 && info.outputChannels > 0 )\r
-    info.isDefaultOutput = true;\r
-  if ( device == 0 && info.inputChannels > 0 )\r
-    info.isDefaultInput = true;\r
-\r
-  jack_client_close(client);\r
-  info.probed = true;\r
-  return info;\r
-}\r
-\r
-static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
-\r
-  RtApiJack *object = (RtApiJack *) info->object;\r
-  if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1;\r
-\r
-  return 0;\r
-}\r
-\r
-// This function will be called by a spawned thread when the Jack\r
-// server signals that it is shutting down.  It is necessary to handle\r
-// it this way because the jackShutdown() function must return before\r
-// the jack_deactivate() function (in closeStream()) will return.\r
-static void *jackCloseStream( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiJack *object = (RtApiJack *) info->object;\r
-\r
-  object->closeStream();\r
-\r
-  pthread_exit( NULL );\r
-}\r
-static void jackShutdown( void *infoPointer )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) infoPointer;\r
-  RtApiJack *object = (RtApiJack *) info->object;\r
-\r
-  // Check current stream state.  If stopped, then we'll assume this\r
-  // was called as a result of a call to RtApiJack::stopStream (the\r
-  // deactivation of a client handle causes this function to be called).\r
-  // If not, we'll assume the Jack server is shutting down or some\r
-  // other problem occurred and we should close the stream.\r
-  if ( object->isStreamRunning() == false ) return;\r
-\r
-  ThreadHandle threadId;\r
-  pthread_create( &threadId, NULL, jackCloseStream, info );\r
-  std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;\r
-}\r
-\r
-static int jackXrun( void *infoPointer )\r
-{\r
-  JackHandle *handle = (JackHandle *) infoPointer;\r
-\r
-  if ( handle->ports[0] ) handle->xrun[0] = true;\r
-  if ( handle->ports[1] ) handle->xrun[1] = true;\r
-\r
-  return 0;\r
-}\r
-\r
-bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                   unsigned int firstChannel, unsigned int sampleRate,\r
-                                   RtAudioFormat format, unsigned int *bufferSize,\r
-                                   RtAudio::StreamOptions *options )\r
-{\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-\r
-  // Look for jack server and try to become a client (only do once per stream).\r
-  jack_client_t *client = 0;\r
-  if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {\r
-    jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;\r
-    jack_status_t *status = NULL;\r
-    if ( options && !options->streamName.empty() )\r
-      client = jack_client_open( options->streamName.c_str(), jackoptions, status );\r
-    else\r
-      client = jack_client_open( "RtApiJack", jackoptions, status );\r
-    if ( client == 0 ) {\r
-      errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";\r
-      error( RtAudioError::WARNING );\r
-      return FAILURE;\r
-    }\r
-  }\r
-  else {\r
-    // The handle must have been created on an earlier pass.\r
-    client = handle->client;\r
-  }\r
-\r
-  const char **ports;\r
-  std::string port, previousPort, deviceName;\r
-  unsigned int nPorts = 0, nDevices = 0;\r
-  ports = jack_get_ports( client, NULL, NULL, 0 );\r
-  if ( ports ) {\r
-    // Parse the port names up to the first colon (:).\r
-    size_t iColon = 0;\r
-    do {\r
-      port = (char *) ports[ nPorts ];\r
-      iColon = port.find(":");\r
-      if ( iColon != std::string::npos ) {\r
-        port = port.substr( 0, iColon );\r
-        if ( port != previousPort ) {\r
-          if ( nDevices == device ) deviceName = port;\r
-          nDevices++;\r
-          previousPort = port;\r
-        }\r
-      }\r
-    } while ( ports[++nPorts] );\r
-    free( ports );\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";\r
-    return FAILURE;\r
-  }\r
-\r
-  // Count the available ports containing the client name as device\r
-  // channels.  Jack "input ports" equal RtAudio output channels.\r
-  unsigned int nChannels = 0;\r
-  unsigned long flag = JackPortIsInput;\r
-  if ( mode == INPUT ) flag = JackPortIsOutput;\r
-  ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );\r
-  if ( ports ) {\r
-    while ( ports[ nChannels ] ) nChannels++;\r
-    free( ports );\r
-  }\r
-\r
-  // Compare the jack ports for specified client to the requested number of channels.\r
-  if ( nChannels < (channels + firstChannel) ) {\r
-    errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Check the jack server sample rate.\r
-  unsigned int jackRate = jack_get_sample_rate( client );\r
-  if ( sampleRate != jackRate ) {\r
-    jack_client_close( client );\r
-    errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  stream_.sampleRate = jackRate;\r
-\r
-  // Get the latency of the JACK port.\r
-  ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );\r
-  if ( ports[ firstChannel ] ) {\r
-    // Added by Ge Wang\r
-    jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);\r
-    // the range (usually the min and max are equal)\r
-    jack_latency_range_t latrange; latrange.min = latrange.max = 0;\r
-    // get the latency range\r
-    jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );\r
-    // be optimistic, use the min!\r
-    stream_.latency[mode] = latrange.min;\r
-    //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );\r
-  }\r
-  free( ports );\r
-\r
-  // The jack server always uses 32-bit floating-point data.\r
-  stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
-  stream_.userFormat = format;\r
-\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
-  else stream_.userInterleaved = true;\r
-\r
-  // Jack always uses non-interleaved buffers.\r
-  stream_.deviceInterleaved[mode] = false;\r
-\r
-  // Jack always provides host byte-ordered data.\r
-  stream_.doByteSwap[mode] = false;\r
-\r
-  // Get the buffer size.  The buffer size and number of buffers\r
-  // (periods) is set when the jack server is started.\r
-  stream_.bufferSize = (int) jack_get_buffer_size( client );\r
-  *bufferSize = stream_.bufferSize;\r
-\r
-  stream_.nDeviceChannels[mode] = channels;\r
-  stream_.nUserChannels[mode] = channels;\r
-\r
-  // Set flags for buffer conversion.\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-       stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate our JackHandle structure for the stream.\r
-  if ( handle == 0 ) {\r
-    try {\r
-      handle = new JackHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory.";\r
-      goto error;\r
-    }\r
-\r
-    if ( pthread_cond_init(&handle->condition, NULL) ) {\r
-      errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable.";\r
-      goto error;\r
-    }\r
-    stream_.apiHandle = (void *) handle;\r
-    handle->client = client;\r
-  }\r
-  handle->deviceName[mode] = deviceName;\r
-\r
-  // Allocate necessary internal buffers.\r
-  unsigned long bufferBytes;\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    if ( mode == OUTPUT )\r
-      bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-    else { // mode == INPUT\r
-      bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] );\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);\r
-        if ( bufferBytes < bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  // Allocate memory for the Jack ports (channels) identifiers.\r
-  handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );\r
-  if ( handle->ports[mode] == NULL )  {\r
-    errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory.";\r
-    goto error;\r
-  }\r
-\r
-  stream_.device[mode] = device;\r
-  stream_.channelOffset[mode] = firstChannel;\r
-  stream_.state = STREAM_STOPPED;\r
-  stream_.callbackInfo.object = (void *) this;\r
-\r
-  if ( stream_.mode == OUTPUT && mode == INPUT )\r
-    // We had already set up the stream for output.\r
-    stream_.mode = DUPLEX;\r
-  else {\r
-    stream_.mode = mode;\r
-    jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );\r
-    jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );\r
-    jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );\r
-  }\r
-\r
-  // Register our ports.\r
-  char label[64];\r
-  if ( mode == OUTPUT ) {\r
-    for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
-      snprintf( label, 64, "outport %d", i );\r
-      handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,\r
-                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );\r
-    }\r
-  }\r
-  else {\r
-    for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
-      snprintf( label, 64, "inport %d", i );\r
-      handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,\r
-                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );\r
-    }\r
-  }\r
-\r
-  // Setup the buffer conversion information structure.  We don't use\r
-  // buffers to do channel offsets, so we override that parameter\r
-  // here.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );\r
-\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( handle ) {\r
-    pthread_cond_destroy( &handle->condition );\r
-    jack_client_close( handle->client );\r
-\r
-    if ( handle->ports[0] ) free( handle->ports[0] );\r
-    if ( handle->ports[1] ) free( handle->ports[1] );\r
-\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiJack :: closeStream( void )\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiJack::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-  if ( handle ) {\r
-\r
-    if ( stream_.state == STREAM_RUNNING )\r
-      jack_deactivate( handle->client );\r
-\r
-    jack_client_close( handle->client );\r
-  }\r
-\r
-  if ( handle ) {\r
-    if ( handle->ports[0] ) free( handle->ports[0] );\r
-    if ( handle->ports[1] ) free( handle->ports[1] );\r
-    pthread_cond_destroy( &handle->condition );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-void RtApiJack :: startStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiJack::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-  int result = jack_activate( handle->client );\r
-  if ( result ) {\r
-    errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";\r
-    goto unlock;\r
-  }\r
-\r
-  const char **ports;\r
-\r
-  // Get the list of available ports.\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    result = 1;\r
-    ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);\r
-    if ( ports == NULL) {\r
-      errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";\r
-      goto unlock;\r
-    }\r
-\r
-    // Now make the port connections.  Since RtAudio wasn't designed to\r
-    // allow the user to select particular channels of a device, we'll\r
-    // just open the first "nChannels" ports with offset.\r
-    for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
-      result = 1;\r
-      if ( ports[ stream_.channelOffset[0] + i ] )\r
-        result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );\r
-      if ( result ) {\r
-        free( ports );\r
-        errorText_ = "RtApiJack::startStream(): error connecting output ports!";\r
-        goto unlock;\r
-      }\r
-    }\r
-    free(ports);\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-    result = 1;\r
-    ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );\r
-    if ( ports == NULL) {\r
-      errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";\r
-      goto unlock;\r
-    }\r
-\r
-    // Now make the port connections.  See note above.\r
-    for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
-      result = 1;\r
-      if ( ports[ stream_.channelOffset[1] + i ] )\r
-        result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );\r
-      if ( result ) {\r
-        free( ports );\r
-        errorText_ = "RtApiJack::startStream(): error connecting input ports!";\r
-        goto unlock;\r
-      }\r
-    }\r
-    free(ports);\r
-  }\r
-\r
-  handle->drainCounter = 0;\r
-  handle->internalDrain = false;\r
-  stream_.state = STREAM_RUNNING;\r
-\r
- unlock:\r
-  if ( result == 0 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiJack :: stopStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    if ( handle->drainCounter == 0 ) {\r
-      handle->drainCounter = 2;\r
-      pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled\r
-    }\r
-  }\r
-\r
-  jack_deactivate( handle->client );\r
-  stream_.state = STREAM_STOPPED;\r
-}\r
-\r
-void RtApiJack :: abortStream( void )\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-  handle->drainCounter = 2;\r
-\r
-  stopStream();\r
-}\r
-\r
-// This function will be called by a spawned thread when the user\r
-// callback function signals that the stream should be stopped or\r
-// aborted.  It is necessary to handle it this way because the\r
-// callbackEvent() function must return before the jack_deactivate()\r
-// function will return.\r
-static void *jackStopStream( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiJack *object = (RtApiJack *) info->object;\r
-\r
-  object->stopStream();\r
-  pthread_exit( NULL );\r
-}\r
-\r
-bool RtApiJack :: callbackEvent( unsigned long nframes )\r
-{\r
-  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return FAILURE;\r
-  }\r
-  if ( stream_.bufferSize != nframes ) {\r
-    errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";\r
-    error( RtAudioError::WARNING );\r
-    return FAILURE;\r
-  }\r
-\r
-  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
-  JackHandle *handle = (JackHandle *) stream_.apiHandle;\r
-\r
-  // Check if we were draining the stream and signal is finished.\r
-  if ( handle->drainCounter > 3 ) {\r
-    ThreadHandle threadId;\r
-\r
-    stream_.state = STREAM_STOPPING;\r
-    if ( handle->internalDrain == true )\r
-      pthread_create( &threadId, NULL, jackStopStream, info );\r
-    else\r
-      pthread_cond_signal( &handle->condition );\r
-    return SUCCESS;\r
-  }\r
-\r
-  // Invoke user callback first, to get fresh output data.\r
-  if ( handle->drainCounter == 0 ) {\r
-    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
-    double streamTime = getStreamTime();\r
-    RtAudioStreamStatus status = 0;\r
-    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
-      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-      handle->xrun[0] = false;\r
-    }\r
-    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
-      status |= RTAUDIO_INPUT_OVERFLOW;\r
-      handle->xrun[1] = false;\r
-    }\r
-    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                                  stream_.bufferSize, streamTime, status, info->userData );\r
-    if ( cbReturnValue == 2 ) {\r
-      stream_.state = STREAM_STOPPING;\r
-      handle->drainCounter = 2;\r
-      ThreadHandle id;\r
-      pthread_create( &id, NULL, jackStopStream, info );\r
-      return SUCCESS;\r
-    }\r
-    else if ( cbReturnValue == 1 ) {\r
-      handle->drainCounter = 1;\r
-      handle->internalDrain = true;\r
-    }\r
-  }\r
-\r
-  jack_default_audio_sample_t *jackbuffer;\r
-  unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t );\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
-\r
-      for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {\r
-        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
-        memset( jackbuffer, 0, bufferBytes );\r
-      }\r
-\r
-    }\r
-    else if ( stream_.doConvertBuffer[0] ) {\r
-\r
-      convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-\r
-      for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {\r
-        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
-        memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );\r
-      }\r
-    }\r
-    else { // no buffer conversion\r
-      for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {\r
-        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );\r
-        memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );\r
-      }\r
-    }\r
-  }\r
-\r
-  // Don't bother draining input\r
-  if ( handle->drainCounter ) {\r
-    handle->drainCounter++;\r
-    goto unlock;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    if ( stream_.doConvertBuffer[1] ) {\r
-      for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {\r
-        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );\r
-        memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );\r
-      }\r
-      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
-    }\r
-    else { // no buffer conversion\r
-      for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {\r
-        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );\r
-        memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );\r
-      }\r
-    }\r
-  }\r
-\r
- unlock:\r
-  RtApi::tickStreamTime();\r
-  return SUCCESS;\r
-}\r
-  //******************** End of __UNIX_JACK__ *********************//\r
-#endif\r
-\r
-#if defined(__WINDOWS_ASIO__) // ASIO API on Windows\r
-\r
-// The ASIO API is designed around a callback scheme, so this\r
-// implementation is similar to that used for OS-X CoreAudio and Linux\r
-// Jack.  The primary constraint with ASIO is that it only allows\r
-// access to a single driver at a time.  Thus, it is not possible to\r
-// have more than one simultaneous RtAudio stream.\r
-//\r
-// This implementation also requires a number of external ASIO files\r
-// and a few global variables.  The ASIO callback scheme does not\r
-// allow for the passing of user data, so we must create a global\r
-// pointer to our callbackInfo structure.\r
-//\r
-// On unix systems, we make use of a pthread condition variable.\r
-// Since there is no equivalent in Windows, I hacked something based\r
-// on information found in\r
-// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.\r
-\r
-#include "asiosys.h"\r
-#include "asio.h"\r
-#include "iasiothiscallresolver.h"\r
-#include "asiodrivers.h"\r
-#include <cmath>\r
-\r
-static AsioDrivers drivers;\r
-static ASIOCallbacks asioCallbacks;\r
-static ASIODriverInfo driverInfo;\r
-static CallbackInfo *asioCallbackInfo;\r
-static bool asioXRun;\r
-\r
-struct AsioHandle {\r
-  int drainCounter;       // Tracks callback counts when draining\r
-  bool internalDrain;     // Indicates if stop is initiated from callback or not.\r
-  ASIOBufferInfo *bufferInfos;\r
-  HANDLE condition;\r
-\r
-  AsioHandle()\r
-    :drainCounter(0), internalDrain(false), bufferInfos(0) {}\r
-};\r
-\r
-// Function declarations (definitions at end of section)\r
-static const char* getAsioErrorString( ASIOError result );\r
-static void sampleRateChanged( ASIOSampleRate sRate );\r
-static long asioMessages( long selector, long value, void* message, double* opt );\r
-\r
-RtApiAsio :: RtApiAsio()\r
-{\r
-  // ASIO cannot run on a multi-threaded appartment. You can call\r
-  // CoInitialize beforehand, but it must be for appartment threading\r
-  // (in which case, CoInitilialize will return S_FALSE here).\r
-  coInitialized_ = false;\r
-  HRESULT hr = CoInitialize( NULL ); \r
-  if ( FAILED(hr) ) {\r
-    errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";\r
-    error( RtAudioError::WARNING );\r
-  }\r
-  coInitialized_ = true;\r
-\r
-  drivers.removeCurrentDriver();\r
-  driverInfo.asioVersion = 2;\r
-\r
-  // See note in DirectSound implementation about GetDesktopWindow().\r
-  driverInfo.sysRef = GetForegroundWindow();\r
-}\r
-\r
-RtApiAsio :: ~RtApiAsio()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-  if ( coInitialized_ ) CoUninitialize();\r
-}\r
-\r
-unsigned int RtApiAsio :: getDeviceCount( void )\r
-{\r
-  return (unsigned int) drivers.asioGetNumDev();\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  // Get device ID\r
-  unsigned int nDevices = getDeviceCount();\r
-  if ( nDevices == 0 ) {\r
-    errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  // If a stream is already open, we cannot probe other devices.  Thus, use the saved results.\r
-  if ( stream_.state != STREAM_CLOSED ) {\r
-    if ( device >= devices_.size() ) {\r
-      errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";\r
-      error( RtAudioError::WARNING );\r
-      return info;\r
-    }\r
-    return devices_[ device ];\r
-  }\r
-\r
-  char driverName[32];\r
-  ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  info.name = driverName;\r
-\r
-  if ( !drivers.loadDriver( driverName ) ) {\r
-    errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  result = ASIOInit( &driverInfo );\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Determine the device channel information.\r
-  long inputChannels, outputChannels;\r
-  result = ASIOGetChannels( &inputChannels, &outputChannels );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  info.outputChannels = outputChannels;\r
-  info.inputChannels = inputChannels;\r
-  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
-    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-\r
-  // Determine the supported sample rates.\r
-  info.sampleRates.clear();\r
-  for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
-    result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );\r
-    if ( result == ASE_OK )\r
-      info.sampleRates.push_back( SAMPLE_RATES[i] );\r
-  }\r
-\r
-  // Determine supported data types ... just check first channel and assume rest are the same.\r
-  ASIOChannelInfo channelInfo;\r
-  channelInfo.channel = 0;\r
-  channelInfo.isInput = true;\r
-  if ( info.inputChannels <= 0 ) channelInfo.isInput = false;\r
-  result = ASIOGetChannelInfo( &channelInfo );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  info.nativeFormats = 0;\r
-  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )\r
-    info.nativeFormats |= RTAUDIO_SINT16;\r
-  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )\r
-    info.nativeFormats |= RTAUDIO_SINT32;\r
-  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )\r
-    info.nativeFormats |= RTAUDIO_FLOAT32;\r
-  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )\r
-    info.nativeFormats |= RTAUDIO_FLOAT64;\r
-  else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )\r
-    info.nativeFormats |= RTAUDIO_SINT24;\r
-\r
-  if ( info.outputChannels > 0 )\r
-    if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;\r
-  if ( info.inputChannels > 0 )\r
-    if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;\r
-\r
-  info.probed = true;\r
-  drivers.removeCurrentDriver();\r
-  return info;\r
-}\r
-\r
-static void bufferSwitch( long index, ASIOBool /*processNow*/ )\r
-{\r
-  RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;\r
-  object->callbackEvent( index );\r
-}\r
-\r
-void RtApiAsio :: saveDeviceInfo( void )\r
-{\r
-  devices_.clear();\r
-\r
-  unsigned int nDevices = getDeviceCount();\r
-  devices_.resize( nDevices );\r
-  for ( unsigned int i=0; i<nDevices; i++ )\r
-    devices_[i] = getDeviceInfo( i );\r
-}\r
-\r
-bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                   unsigned int firstChannel, unsigned int sampleRate,\r
-                                   RtAudioFormat format, unsigned int *bufferSize,\r
-                                   RtAudio::StreamOptions *options )\r
-{\r
-  // For ASIO, a duplex stream MUST use the same driver.\r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {\r
-    errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";\r
-    return FAILURE;\r
-  }\r
-\r
-  char driverName[32];\r
-  ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: unable to get driver name (" << getAsioErrorString( result ) << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Only load the driver once for duplex stream.\r
-  if ( mode != INPUT || stream_.mode != OUTPUT ) {\r
-    // The getDeviceInfo() function will not work when a stream is open\r
-    // because ASIO does not allow multiple devices to run at the same\r
-    // time.  Thus, we'll probe the system before opening a stream and\r
-    // save the results for use by getDeviceInfo().\r
-    this->saveDeviceInfo();\r
-\r
-    if ( !drivers.loadDriver( driverName ) ) {\r
-      errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    result = ASIOInit( &driverInfo );\r
-    if ( result != ASE_OK ) {\r
-      errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // Check the device channel count.\r
-  long inputChannels, outputChannels;\r
-  result = ASIOGetChannels( &inputChannels, &outputChannels );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||\r
-       ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  stream_.nDeviceChannels[mode] = channels;\r
-  stream_.nUserChannels[mode] = channels;\r
-  stream_.channelOffset[mode] = firstChannel;\r
-\r
-  // Verify the sample rate is supported.\r
-  result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Get the current sample rate\r
-  ASIOSampleRate currentRate;\r
-  result = ASIOGetSampleRate( &currentRate );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the sample rate only if necessary\r
-  if ( currentRate != sampleRate ) {\r
-    result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );\r
-    if ( result != ASE_OK ) {\r
-      drivers.removeCurrentDriver();\r
-      errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // Determine the driver data type.\r
-  ASIOChannelInfo channelInfo;\r
-  channelInfo.channel = 0;\r
-  if ( mode == OUTPUT ) channelInfo.isInput = false;\r
-  else channelInfo.isInput = true;\r
-  result = ASIOGetChannelInfo( &channelInfo );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Assuming WINDOWS host is always little-endian.\r
-  stream_.doByteSwap[mode] = false;\r
-  stream_.userFormat = format;\r
-  stream_.deviceFormat[mode] = 0;\r
-  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-    if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;\r
-  }\r
-  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-    if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;\r
-  }\r
-  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
-    if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;\r
-  }\r
-  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;\r
-    if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;\r
-  }\r
-  else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-    if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;\r
-  }\r
-\r
-  if ( stream_.deviceFormat[mode] == 0 ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the buffer size.  For a duplex stream, this will end up\r
-  // setting the buffer size based on the input constraints, which\r
-  // should be ok.\r
-  long minSize, maxSize, preferSize, granularity;\r
-  result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );\r
-  if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
-  else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
-  else if ( granularity == -1 ) {\r
-    // Make sure bufferSize is a power of two.\r
-    int log2_of_min_size = 0;\r
-    int log2_of_max_size = 0;\r
-\r
-    for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
-      if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
-      if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
-    }\r
-\r
-    long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
-    int min_delta_num = log2_of_min_size;\r
-\r
-    for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
-      long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
-      if (current_delta < min_delta) {\r
-        min_delta = current_delta;\r
-        min_delta_num = i;\r
-      }\r
-    }\r
-\r
-    *bufferSize = ( (unsigned int)1 << min_delta_num );\r
-    if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
-    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
-  }\r
-  else if ( granularity != 0 ) {\r
-    // Set to an even multiple of granularity, rounding up.\r
-    *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
-  }\r
-\r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {\r
-    drivers.removeCurrentDriver();\r
-    errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";\r
-    return FAILURE;\r
-  }\r
-\r
-  stream_.bufferSize = *bufferSize;\r
-  stream_.nBuffers = 2;\r
-\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
-  else stream_.userInterleaved = true;\r
-\r
-  // ASIO always uses non-interleaved buffers.\r
-  stream_.deviceInterleaved[mode] = false;\r
-\r
-  // Allocate, if necessary, our AsioHandle structure for the stream.\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-  if ( handle == 0 ) {\r
-    try {\r
-      handle = new AsioHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      //if ( handle == NULL ) {    \r
-      drivers.removeCurrentDriver();\r
-      errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";\r
-      return FAILURE;\r
-    }\r
-    handle->bufferInfos = 0;\r
-\r
-    // Create a manual-reset event.\r
-    handle->condition = CreateEvent( NULL,   // no security\r
-                                     TRUE,   // manual-reset\r
-                                     FALSE,  // non-signaled initially\r
-                                     NULL ); // unnamed\r
-    stream_.apiHandle = (void *) handle;\r
-  }\r
-\r
-  // Create the ASIO internal buffers.  Since RtAudio sets up input\r
-  // and output separately, we'll have to dispose of previously\r
-  // created output buffers for a duplex stream.\r
-  long inputLatency, outputLatency;\r
-  if ( mode == INPUT && stream_.mode == OUTPUT ) {\r
-    ASIODisposeBuffers();\r
-    if ( handle->bufferInfos ) free( handle->bufferInfos );\r
-  }\r
-\r
-  // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.\r
-  bool buffersAllocated = false;\r
-  unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
-  handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );\r
-  if ( handle->bufferInfos == NULL ) {\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";\r
-    errorText_ = errorStream_.str();\r
-    goto error;\r
-  }\r
-\r
-  ASIOBufferInfo *infos;\r
-  infos = handle->bufferInfos;\r
-  for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {\r
-    infos->isInput = ASIOFalse;\r
-    infos->channelNum = i + stream_.channelOffset[0];\r
-    infos->buffers[0] = infos->buffers[1] = 0;\r
-  }\r
-  for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {\r
-    infos->isInput = ASIOTrue;\r
-    infos->channelNum = i + stream_.channelOffset[1];\r
-    infos->buffers[0] = infos->buffers[1] = 0;\r
-  }\r
-\r
-  // Set up the ASIO callback structure and create the ASIO data buffers.\r
-  asioCallbacks.bufferSwitch = &bufferSwitch;\r
-  asioCallbacks.sampleRateDidChange = &sampleRateChanged;\r
-  asioCallbacks.asioMessage = &asioMessages;\r
-  asioCallbacks.bufferSwitchTimeInfo = NULL;\r
-  result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";\r
-    errorText_ = errorStream_.str();\r
-    goto error;\r
-  }\r
-  buffersAllocated = true;\r
-\r
-  // Set flags for buffer conversion.\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-       stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate necessary internal buffers\r
-  unsigned long bufferBytes;\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.sampleRate = sampleRate;\r
-  stream_.device[mode] = device;\r
-  stream_.state = STREAM_STOPPED;\r
-  asioCallbackInfo = &stream_.callbackInfo;\r
-  stream_.callbackInfo.object = (void *) this;\r
-  if ( stream_.mode == OUTPUT && mode == INPUT )\r
-    // We had already set up an output stream.\r
-    stream_.mode = DUPLEX;\r
-  else\r
-    stream_.mode = mode;\r
-\r
-  // Determine device latencies\r
-  result = ASIOGetLatencies( &inputLatency, &outputLatency );\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING); // warn but don't fail\r
-  }\r
-  else {\r
-    stream_.latency[0] = outputLatency;\r
-    stream_.latency[1] = inputLatency;\r
-  }\r
-\r
-  // Setup the buffer conversion information structure.  We don't use\r
-  // buffers to do channel offsets, so we override that parameter\r
-  // here.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );\r
-\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( buffersAllocated )\r
-    ASIODisposeBuffers();\r
-  drivers.removeCurrentDriver();\r
-\r
-  if ( handle ) {\r
-    CloseHandle( handle->condition );\r
-    if ( handle->bufferInfos )\r
-      free( handle->bufferInfos );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiAsio :: closeStream()\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiAsio::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    stream_.state = STREAM_STOPPED;\r
-    ASIOStop();\r
-  }\r
-  ASIODisposeBuffers();\r
-  drivers.removeCurrentDriver();\r
-\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-  if ( handle ) {\r
-    CloseHandle( handle->condition );\r
-    if ( handle->bufferInfos )\r
-      free( handle->bufferInfos );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-bool stopThreadCalled = false;\r
-\r
-void RtApiAsio :: startStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiAsio::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-  ASIOError result = ASIOStart();\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device.";\r
-    errorText_ = errorStream_.str();\r
-    goto unlock;\r
-  }\r
-\r
-  handle->drainCounter = 0;\r
-  handle->internalDrain = false;\r
-  ResetEvent( handle->condition );\r
-  stream_.state = STREAM_RUNNING;\r
-  asioXRun = false;\r
-\r
- unlock:\r
-  stopThreadCalled = false;\r
-\r
-  if ( result == ASE_OK ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiAsio :: stopStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    if ( handle->drainCounter == 0 ) {\r
-      handle->drainCounter = 2;\r
-      WaitForSingleObject( handle->condition, INFINITE );  // block until signaled\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-\r
-  ASIOError result = ASIOStop();\r
-  if ( result != ASE_OK ) {\r
-    errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device.";\r
-    errorText_ = errorStream_.str();\r
-  }\r
-\r
-  if ( result == ASE_OK ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiAsio :: abortStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // The following lines were commented-out because some behavior was\r
-  // noted where the device buffers need to be zeroed to avoid\r
-  // continuing sound, even when the device buffers are completely\r
-  // disposed.  So now, calling abort is the same as calling stop.\r
-  // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-  // handle->drainCounter = 2;\r
-  stopStream();\r
-}\r
-\r
-// This function will be called by a spawned thread when the user\r
-// callback function signals that the stream should be stopped or\r
-// aborted.  It is necessary to handle it this way because the\r
-// callbackEvent() function must return before the ASIOStop()\r
-// function will return.\r
-static unsigned __stdcall asioStopStream( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiAsio *object = (RtApiAsio *) info->object;\r
-\r
-  object->stopStream();\r
-  _endthreadex( 0 );\r
-  return 0;\r
-}\r
-\r
-bool RtApiAsio :: callbackEvent( long bufferIndex )\r
-{\r
-  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return FAILURE;\r
-  }\r
-\r
-  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
-\r
-  // Check if we were draining the stream and signal if finished.\r
-  if ( handle->drainCounter > 3 ) {\r
-\r
-    stream_.state = STREAM_STOPPING;\r
-    if ( handle->internalDrain == false )\r
-      SetEvent( handle->condition );\r
-    else { // spawn a thread to stop the stream\r
-      unsigned threadId;\r
-      stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,\r
-                                                    &stream_.callbackInfo, 0, &threadId );\r
-    }\r
-    return SUCCESS;\r
-  }\r
-\r
-  // Invoke user callback to get fresh output data UNLESS we are\r
-  // draining stream.\r
-  if ( handle->drainCounter == 0 ) {\r
-    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
-    double streamTime = getStreamTime();\r
-    RtAudioStreamStatus status = 0;\r
-    if ( stream_.mode != INPUT && asioXRun == true ) {\r
-      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-      asioXRun = false;\r
-    }\r
-    if ( stream_.mode != OUTPUT && asioXRun == true ) {\r
-      status |= RTAUDIO_INPUT_OVERFLOW;\r
-      asioXRun = false;\r
-    }\r
-    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                                     stream_.bufferSize, streamTime, status, info->userData );\r
-    if ( cbReturnValue == 2 ) {\r
-      stream_.state = STREAM_STOPPING;\r
-      handle->drainCounter = 2;\r
-      unsigned threadId;\r
-      stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,\r
-                                                    &stream_.callbackInfo, 0, &threadId );\r
-      return SUCCESS;\r
-    }\r
-    else if ( cbReturnValue == 1 ) {\r
-      handle->drainCounter = 1;\r
-      handle->internalDrain = true;\r
-    }\r
-  }\r
-\r
-  unsigned int nChannels, bufferBytes, i, j;\r
-  nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );\r
-\r
-    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
-\r
-      for ( i=0, j=0; i<nChannels; i++ ) {\r
-        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
-          memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes );\r
-      }\r
-\r
-    }\r
-    else if ( stream_.doConvertBuffer[0] ) {\r
-\r
-      convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-      if ( stream_.doByteSwap[0] )\r
-        byteSwapBuffer( stream_.deviceBuffer,\r
-                        stream_.bufferSize * stream_.nDeviceChannels[0],\r
-                        stream_.deviceFormat[0] );\r
-\r
-      for ( i=0, j=0; i<nChannels; i++ ) {\r
-        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
-          memcpy( handle->bufferInfos[i].buffers[bufferIndex],\r
-                  &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );\r
-      }\r
-\r
-    }\r
-    else {\r
-\r
-      if ( stream_.doByteSwap[0] )\r
-        byteSwapBuffer( stream_.userBuffer[0],\r
-                        stream_.bufferSize * stream_.nUserChannels[0],\r
-                        stream_.userFormat );\r
-\r
-      for ( i=0, j=0; i<nChannels; i++ ) {\r
-        if ( handle->bufferInfos[i].isInput != ASIOTrue )\r
-          memcpy( handle->bufferInfos[i].buffers[bufferIndex],\r
-                  &stream_.userBuffer[0][bufferBytes*j++], bufferBytes );\r
-      }\r
-\r
-    }\r
-  }\r
-\r
-  // Don't bother draining input\r
-  if ( handle->drainCounter ) {\r
-    handle->drainCounter++;\r
-    goto unlock;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);\r
-\r
-    if (stream_.doConvertBuffer[1]) {\r
-\r
-      // Always interleave ASIO input data.\r
-      for ( i=0, j=0; i<nChannels; i++ ) {\r
-        if ( handle->bufferInfos[i].isInput == ASIOTrue )\r
-          memcpy( &stream_.deviceBuffer[j++*bufferBytes],\r
-                  handle->bufferInfos[i].buffers[bufferIndex],\r
-                  bufferBytes );\r
-      }\r
-\r
-      if ( stream_.doByteSwap[1] )\r
-        byteSwapBuffer( stream_.deviceBuffer,\r
-                        stream_.bufferSize * stream_.nDeviceChannels[1],\r
-                        stream_.deviceFormat[1] );\r
-      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
-\r
-    }\r
-    else {\r
-      for ( i=0, j=0; i<nChannels; i++ ) {\r
-        if ( handle->bufferInfos[i].isInput == ASIOTrue ) {\r
-          memcpy( &stream_.userBuffer[1][bufferBytes*j++],\r
-                  handle->bufferInfos[i].buffers[bufferIndex],\r
-                  bufferBytes );\r
-        }\r
-      }\r
-\r
-      if ( stream_.doByteSwap[1] )\r
-        byteSwapBuffer( stream_.userBuffer[1],\r
-                        stream_.bufferSize * stream_.nUserChannels[1],\r
-                        stream_.userFormat );\r
-    }\r
-  }\r
-\r
- unlock:\r
-  // The following call was suggested by Malte Clasen.  While the API\r
-  // documentation indicates it should not be required, some device\r
-  // drivers apparently do not function correctly without it.\r
-  ASIOOutputReady();\r
-\r
-  RtApi::tickStreamTime();\r
-  return SUCCESS;\r
-}\r
-\r
-static void sampleRateChanged( ASIOSampleRate sRate )\r
-{\r
-  // The ASIO documentation says that this usually only happens during\r
-  // external sync.  Audio processing is not stopped by the driver,\r
-  // actual sample rate might not have even changed, maybe only the\r
-  // sample rate status of an AES/EBU or S/PDIF digital input at the\r
-  // audio device.\r
-\r
-  RtApi *object = (RtApi *) asioCallbackInfo->object;\r
-  try {\r
-    object->stopStream();\r
-  }\r
-  catch ( RtAudioError &exception ) {\r
-    std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;\r
-    return;\r
-  }\r
-\r
-  std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;\r
-}\r
-\r
-static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )\r
-{\r
-  long ret = 0;\r
-\r
-  switch( selector ) {\r
-  case kAsioSelectorSupported:\r
-    if ( value == kAsioResetRequest\r
-         || value == kAsioEngineVersion\r
-         || value == kAsioResyncRequest\r
-         || value == kAsioLatenciesChanged\r
-         // The following three were added for ASIO 2.0, you don't\r
-         // necessarily have to support them.\r
-         || value == kAsioSupportsTimeInfo\r
-         || value == kAsioSupportsTimeCode\r
-         || value == kAsioSupportsInputMonitor)\r
-      ret = 1L;\r
-    break;\r
-  case kAsioResetRequest:\r
-    // Defer the task and perform the reset of the driver during the\r
-    // next "safe" situation.  You cannot reset the driver right now,\r
-    // as this code is called from the driver.  Reset the driver is\r
-    // done by completely destruct is. I.e. ASIOStop(),\r
-    // ASIODisposeBuffers(), Destruction Afterwards you initialize the\r
-    // driver again.\r
-    std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl;\r
-    ret = 1L;\r
-    break;\r
-  case kAsioResyncRequest:\r
-    // This informs the application that the driver encountered some\r
-    // non-fatal data loss.  It is used for synchronization purposes\r
-    // of different media.  Added mainly to work around the Win16Mutex\r
-    // problems in Windows 95/98 with the Windows Multimedia system,\r
-    // which could lose data because the Mutex was held too long by\r
-    // another thread.  However a driver can issue it in other\r
-    // situations, too.\r
-    // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl;\r
-    asioXRun = true;\r
-    ret = 1L;\r
-    break;\r
-  case kAsioLatenciesChanged:\r
-    // This will inform the host application that the drivers were\r
-    // latencies changed.  Beware, it this does not mean that the\r
-    // buffer sizes have changed!  You might need to update internal\r
-    // delay data.\r
-    std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl;\r
-    ret = 1L;\r
-    break;\r
-  case kAsioEngineVersion:\r
-    // Return the supported ASIO version of the host application.  If\r
-    // a host application does not implement this selector, ASIO 1.0\r
-    // is assumed by the driver.\r
-    ret = 2L;\r
-    break;\r
-  case kAsioSupportsTimeInfo:\r
-    // Informs the driver whether the\r
-    // asioCallbacks.bufferSwitchTimeInfo() callback is supported.\r
-    // For compatibility with ASIO 1.0 drivers the host application\r
-    // should always support the "old" bufferSwitch method, too.\r
-    ret = 0;\r
-    break;\r
-  case kAsioSupportsTimeCode:\r
-    // Informs the driver whether application is interested in time\r
-    // code info.  If an application does not need to know about time\r
-    // code, the driver has less work to do.\r
-    ret = 0;\r
-    break;\r
-  }\r
-  return ret;\r
-}\r
-\r
-static const char* getAsioErrorString( ASIOError result )\r
-{\r
-  struct Messages \r
-  {\r
-    ASIOError value;\r
-    const char*message;\r
-  };\r
-\r
-  static const Messages m[] = \r
-    {\r
-      {   ASE_NotPresent,    "Hardware input or output is not present or available." },\r
-      {   ASE_HWMalfunction,  "Hardware is malfunctioning." },\r
-      {   ASE_InvalidParameter, "Invalid input parameter." },\r
-      {   ASE_InvalidMode,      "Invalid mode." },\r
-      {   ASE_SPNotAdvancing,     "Sample position not advancing." },\r
-      {   ASE_NoClock,            "Sample clock or rate cannot be determined or is not present." },\r
-      {   ASE_NoMemory,           "Not enough memory to complete the request." }\r
-    };\r
-\r
-  for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )\r
-    if ( m[i].value == result ) return m[i].message;\r
-\r
-  return "Unknown error.";\r
-}\r
-\r
-//******************** End of __WINDOWS_ASIO__ *********************//\r
-#endif\r
-\r
-\r
-#if defined(__WINDOWS_WASAPI__) // Windows WASAPI API\r
-\r
-// Authored by Marcus Tomlinson <themarcustomlinson@gmail.com>, April 2014\r
-// - Introduces support for the Windows WASAPI API\r
-// - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required\r
-// - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface\r
-// - Includes automatic internal conversion of sample rate and buffer size between hardware and the user\r
-\r
-#ifndef INITGUID\r
-  #define INITGUID\r
-#endif\r
-#include <audioclient.h>\r
-#include <avrt.h>\r
-#include <mmdeviceapi.h>\r
-#include <functiondiscoverykeys_devpkey.h>\r
-\r
-//=============================================================================\r
-\r
-#define SAFE_RELEASE( objectPtr )\\r
-if ( objectPtr )\\r
-{\\r
-  objectPtr->Release();\\r
-  objectPtr = NULL;\\r
-}\r
-\r
-typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex );\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-// WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size.\r
-// Therefore we must perform all necessary conversions to user buffers in order to satisfy these\r
-// requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to\r
-// provide intermediate storage for read / write synchronization.\r
-class WasapiBuffer\r
-{\r
-public:\r
-  WasapiBuffer()\r
-    : buffer_( NULL ),\r
-      bufferSize_( 0 ),\r
-      inIndex_( 0 ),\r
-      outIndex_( 0 ) {}\r
-\r
-  ~WasapiBuffer() {\r
-    delete buffer_;\r
-  }\r
-\r
-  // sets the length of the internal ring buffer\r
-  void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {\r
-    delete buffer_;\r
-\r
-    buffer_ = ( char* ) calloc( bufferSize, formatBytes );\r
-\r
-    bufferSize_ = bufferSize;\r
-    inIndex_ = 0;\r
-    outIndex_ = 0;\r
-  }\r
-\r
-  // attempt to push a buffer into the ring buffer at the current "in" index\r
-  bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )\r
-  {\r
-    if ( !buffer ||                 // incoming buffer is NULL\r
-         bufferSize == 0 ||         // incoming buffer has no data\r
-         bufferSize > bufferSize_ ) // incoming buffer too large\r
-    {\r
-      return false;\r
-    }\r
-\r
-    unsigned int relOutIndex = outIndex_;\r
-    unsigned int inIndexEnd = inIndex_ + bufferSize;\r
-    if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) {\r
-      relOutIndex += bufferSize_;\r
-    }\r
-\r
-    // "in" index can end on the "out" index but cannot begin at it\r
-    if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {\r
-      return false; // not enough space between "in" index and "out" index\r
-    }\r
-\r
-    // copy buffer from external to internal\r
-    int fromZeroSize = inIndex_ + bufferSize - bufferSize_;\r
-    fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;\r
-    int fromInSize = bufferSize - fromZeroSize;\r
-\r
-    switch( format )\r
-      {\r
-      case RTAUDIO_SINT8:\r
-        memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) );\r
-        memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) );\r
-        break;\r
-      case RTAUDIO_SINT16:\r
-        memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) );\r
-        memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) );\r
-        break;\r
-      case RTAUDIO_SINT24:\r
-        memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) );\r
-        memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) );\r
-        break;\r
-      case RTAUDIO_SINT32:\r
-        memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) );\r
-        memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) );\r
-        break;\r
-      case RTAUDIO_FLOAT32:\r
-        memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) );\r
-        memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) );\r
-        break;\r
-      case RTAUDIO_FLOAT64:\r
-        memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) );\r
-        memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) );\r
-        break;\r
-    }\r
-\r
-    // update "in" index\r
-    inIndex_ += bufferSize;\r
-    inIndex_ %= bufferSize_;\r
-\r
-    return true;\r
-  }\r
-\r
-  // attempt to pull a buffer from the ring buffer from the current "out" index\r
-  bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )\r
-  {\r
-    if ( !buffer ||                 // incoming buffer is NULL\r
-         bufferSize == 0 ||         // incoming buffer has no data\r
-         bufferSize > bufferSize_ ) // incoming buffer too large\r
-    {\r
-      return false;\r
-    }\r
-\r
-    unsigned int relInIndex = inIndex_;\r
-    unsigned int outIndexEnd = outIndex_ + bufferSize;\r
-    if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) {\r
-      relInIndex += bufferSize_;\r
-    }\r
-\r
-    // "out" index can begin at and end on the "in" index\r
-    if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {\r
-      return false; // not enough space between "out" index and "in" index\r
-    }\r
-\r
-    // copy buffer from internal to external\r
-    int fromZeroSize = outIndex_ + bufferSize - bufferSize_;\r
-    fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;\r
-    int fromOutSize = bufferSize - fromZeroSize;\r
-\r
-    switch( format )\r
-    {\r
-      case RTAUDIO_SINT8:\r
-        memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) );\r
-        memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) );\r
-        break;\r
-      case RTAUDIO_SINT16:\r
-        memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) );\r
-        memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) );\r
-        break;\r
-      case RTAUDIO_SINT24:\r
-        memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) );\r
-        memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) );\r
-        break;\r
-      case RTAUDIO_SINT32:\r
-        memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) );\r
-        memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) );\r
-        break;\r
-      case RTAUDIO_FLOAT32:\r
-        memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) );\r
-        memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) );\r
-        break;\r
-      case RTAUDIO_FLOAT64:\r
-        memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) );\r
-        memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) );\r
-        break;\r
-    }\r
-\r
-    // update "out" index\r
-    outIndex_ += bufferSize;\r
-    outIndex_ %= bufferSize_;\r
-\r
-    return true;\r
-  }\r
-\r
-private:\r
-  char* buffer_;\r
-  unsigned int bufferSize_;\r
-  unsigned int inIndex_;\r
-  unsigned int outIndex_;\r
-};\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate\r
-// between HW and the user. The convertBufferWasapi function is used to perform this conversion\r
-// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.\r
-// This sample rate converter favors speed over quality, and works best with conversions between\r
-// one rate and its multiple.\r
-void convertBufferWasapi( char* outBuffer,\r
-                          const char* inBuffer,\r
-                          const unsigned int& channelCount,\r
-                          const unsigned int& inSampleRate,\r
-                          const unsigned int& outSampleRate,\r
-                          const unsigned int& inSampleCount,\r
-                          unsigned int& outSampleCount,\r
-                          const RtAudioFormat& format )\r
-{\r
-  // calculate the new outSampleCount and relative sampleStep\r
-  float sampleRatio = ( float ) outSampleRate / inSampleRate;\r
-  float sampleStep = 1.0f / sampleRatio;\r
-  float inSampleFraction = 0.0f;\r
-\r
-  outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );\r
-\r
-  // frame-by-frame, copy each relative input sample into it's corresponding output sample\r
-  for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )\r
-  {\r
-    unsigned int inSample = ( unsigned int ) inSampleFraction;\r
-\r
-    switch ( format )\r
-    {\r
-      case RTAUDIO_SINT8:\r
-        memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );\r
-        break;\r
-      case RTAUDIO_SINT16:\r
-        memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );\r
-        break;\r
-      case RTAUDIO_SINT24:\r
-        memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );\r
-        break;\r
-      case RTAUDIO_SINT32:\r
-        memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );\r
-        break;\r
-      case RTAUDIO_FLOAT32:\r
-        memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );\r
-        break;\r
-      case RTAUDIO_FLOAT64:\r
-        memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );\r
-        break;\r
-    }\r
-\r
-    // jump to next in sample\r
-    inSampleFraction += sampleStep;\r
-  }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-// A structure to hold various information related to the WASAPI implementation.\r
-struct WasapiHandle\r
-{\r
-  IAudioClient* captureAudioClient;\r
-  IAudioClient* renderAudioClient;\r
-  IAudioCaptureClient* captureClient;\r
-  IAudioRenderClient* renderClient;\r
-  HANDLE captureEvent;\r
-  HANDLE renderEvent;\r
-\r
-  WasapiHandle()\r
-  : captureAudioClient( NULL ),\r
-    renderAudioClient( NULL ),\r
-    captureClient( NULL ),\r
-    renderClient( NULL ),\r
-    captureEvent( NULL ),\r
-    renderEvent( NULL ) {}\r
-};\r
-\r
-//=============================================================================\r
-\r
-RtApiWasapi::RtApiWasapi()\r
-  : coInitialized_( false ), deviceEnumerator_( NULL )\r
-{\r
-  // WASAPI can run either apartment or multi-threaded\r
-  HRESULT hr = CoInitialize( NULL );\r
-  if ( !FAILED( hr ) )\r
-    coInitialized_ = true;\r
-\r
-  // Instantiate device enumerator\r
-  hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,\r
-                         CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),\r
-                         ( void** ) &deviceEnumerator_ );\r
-\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";\r
-    error( RtAudioError::DRIVER_ERROR );\r
-  }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-RtApiWasapi::~RtApiWasapi()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED )\r
-    closeStream();\r
-\r
-  SAFE_RELEASE( deviceEnumerator_ );\r
-\r
-  // If this object previously called CoInitialize()\r
-  if ( coInitialized_ )\r
-    CoUninitialize();\r
-}\r
-\r
-//=============================================================================\r
-\r
-unsigned int RtApiWasapi::getDeviceCount( void )\r
-{\r
-  unsigned int captureDeviceCount = 0;\r
-  unsigned int renderDeviceCount = 0;\r
-\r
-  IMMDeviceCollection* captureDevices = NULL;\r
-  IMMDeviceCollection* renderDevices = NULL;\r
-\r
-  // Count capture devices\r
-  errorText_.clear();\r
-  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = captureDevices->GetCount( &captureDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";\r
-    goto Exit;\r
-  }\r
-\r
-  // Count render devices\r
-  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = renderDevices->GetCount( &renderDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";\r
-    goto Exit;\r
-  }\r
-\r
-Exit:\r
-  // release all references\r
-  SAFE_RELEASE( captureDevices );\r
-  SAFE_RELEASE( renderDevices );\r
-\r
-  if ( errorText_.empty() )\r
-    return captureDeviceCount + renderDeviceCount;\r
-\r
-  error( RtAudioError::DRIVER_ERROR );\r
-  return 0;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  unsigned int captureDeviceCount = 0;\r
-  unsigned int renderDeviceCount = 0;\r
-  std::wstring deviceName;\r
-  std::string defaultDeviceName;\r
-  bool isCaptureDevice = false;\r
-\r
-  PROPVARIANT deviceNameProp;\r
-  PROPVARIANT defaultDeviceNameProp;\r
-\r
-  IMMDeviceCollection* captureDevices = NULL;\r
-  IMMDeviceCollection* renderDevices = NULL;\r
-  IMMDevice* devicePtr = NULL;\r
-  IMMDevice* defaultDevicePtr = NULL;\r
-  IAudioClient* audioClient = NULL;\r
-  IPropertyStore* devicePropStore = NULL;\r
-  IPropertyStore* defaultDevicePropStore = NULL;\r
-\r
-  WAVEFORMATEX* deviceFormat = NULL;\r
-  WAVEFORMATEX* closestMatchFormat = NULL;\r
-\r
-  // probed\r
-  info.probed = false;\r
-\r
-  // Count capture devices\r
-  errorText_.clear();\r
-  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
-  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = captureDevices->GetCount( &captureDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";\r
-    goto Exit;\r
-  }\r
-\r
-  // Count render devices\r
-  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = renderDevices->GetCount( &renderDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";\r
-    goto Exit;\r
-  }\r
-\r
-  // validate device index\r
-  if ( device >= captureDeviceCount + renderDeviceCount ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";\r
-    errorType = RtAudioError::INVALID_USE;\r
-    goto Exit;\r
-  }\r
-\r
-  // determine whether index falls within capture or render devices\r
-  if ( device >= renderDeviceCount ) {\r
-    hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";\r
-      goto Exit;\r
-    }\r
-    isCaptureDevice = true;\r
-  }\r
-  else {\r
-    hr = renderDevices->Item( device, &devicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";\r
-      goto Exit;\r
-    }\r
-    isCaptureDevice = false;\r
-  }\r
-\r
-  // get default device name\r
-  if ( isCaptureDevice ) {\r
-    hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";\r
-      goto Exit;\r
-    }\r
-  }\r
-  else {\r
-    hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";\r
-      goto Exit;\r
-    }\r
-  }\r
-\r
-  hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";\r
-    goto Exit;\r
-  }\r
-  PropVariantInit( &defaultDeviceNameProp );\r
-\r
-  hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";\r
-    goto Exit;\r
-  }\r
-\r
-  deviceName = defaultDeviceNameProp.pwszVal;\r
-  defaultDeviceName = std::string( deviceName.begin(), deviceName.end() );\r
-\r
-  // name\r
-  hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";\r
-    goto Exit;\r
-  }\r
-\r
-  PropVariantInit( &deviceNameProp );\r
-\r
-  hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";\r
-    goto Exit;\r
-  }\r
-\r
-  deviceName = deviceNameProp.pwszVal;\r
-  info.name = std::string( deviceName.begin(), deviceName.end() );\r
-\r
-  // is default\r
-  if ( isCaptureDevice ) {\r
-    info.isDefaultInput = info.name == defaultDeviceName;\r
-    info.isDefaultOutput = false;\r
-  }\r
-  else {\r
-    info.isDefaultInput = false;\r
-    info.isDefaultOutput = info.name == defaultDeviceName;\r
-  }\r
-\r
-  // channel count\r
-  hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = audioClient->GetMixFormat( &deviceFormat );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";\r
-    goto Exit;\r
-  }\r
-\r
-  if ( isCaptureDevice ) {\r
-    info.inputChannels = deviceFormat->nChannels;\r
-    info.outputChannels = 0;\r
-    info.duplexChannels = 0;\r
-  }\r
-  else {\r
-    info.inputChannels = 0;\r
-    info.outputChannels = deviceFormat->nChannels;\r
-    info.duplexChannels = 0;\r
-  }\r
-\r
-  // sample rates\r
-  info.sampleRates.clear();\r
-\r
-  // allow support for all sample rates as we have a built-in sample rate converter\r
-  for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {\r
-    info.sampleRates.push_back( SAMPLE_RATES[i] );\r
-  }\r
-\r
-  // native format\r
-  info.nativeFormats = 0;\r
-\r
-  if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||\r
-       ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&\r
-         ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )\r
-  {\r
-    if ( deviceFormat->wBitsPerSample == 32 ) {\r
-      info.nativeFormats |= RTAUDIO_FLOAT32;\r
-    }\r
-    else if ( deviceFormat->wBitsPerSample == 64 ) {\r
-      info.nativeFormats |= RTAUDIO_FLOAT64;\r
-    }\r
-  }\r
-  else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||\r
-           ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&\r
-             ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )\r
-  {\r
-    if ( deviceFormat->wBitsPerSample == 8 ) {\r
-      info.nativeFormats |= RTAUDIO_SINT8;\r
-    }\r
-    else if ( deviceFormat->wBitsPerSample == 16 ) {\r
-      info.nativeFormats |= RTAUDIO_SINT16;\r
-    }\r
-    else if ( deviceFormat->wBitsPerSample == 24 ) {\r
-      info.nativeFormats |= RTAUDIO_SINT24;\r
-    }\r
-    else if ( deviceFormat->wBitsPerSample == 32 ) {\r
-      info.nativeFormats |= RTAUDIO_SINT32;\r
-    }\r
-  }\r
-\r
-  // probed\r
-  info.probed = true;\r
-\r
-Exit:\r
-  // release all references\r
-  PropVariantClear( &deviceNameProp );\r
-  PropVariantClear( &defaultDeviceNameProp );\r
-\r
-  SAFE_RELEASE( captureDevices );\r
-  SAFE_RELEASE( renderDevices );\r
-  SAFE_RELEASE( devicePtr );\r
-  SAFE_RELEASE( defaultDevicePtr );\r
-  SAFE_RELEASE( audioClient );\r
-  SAFE_RELEASE( devicePropStore );\r
-  SAFE_RELEASE( defaultDevicePropStore );\r
-\r
-  CoTaskMemFree( deviceFormat );\r
-  CoTaskMemFree( closestMatchFormat );\r
-\r
-  if ( !errorText_.empty() )\r
-    error( errorType );\r
-  return info;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-unsigned int RtApiWasapi::getDefaultOutputDevice( void )\r
-{\r
-  for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {\r
-    if ( getDeviceInfo( i ).isDefaultOutput ) {\r
-      return i;\r
-    }\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-unsigned int RtApiWasapi::getDefaultInputDevice( void )\r
-{\r
-  for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {\r
-    if ( getDeviceInfo( i ).isDefaultInput ) {\r
-      return i;\r
-    }\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-void RtApiWasapi::closeStream( void )\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiWasapi::closeStream: No open stream to close.";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  if ( stream_.state != STREAM_STOPPED )\r
-    stopStream();\r
-\r
-  // clean up stream memory\r
-  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )\r
-  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )\r
-\r
-  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )\r
-  SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )\r
-\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )\r
-    CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );\r
-\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )\r
-    CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );\r
-\r
-  delete ( WasapiHandle* ) stream_.apiHandle;\r
-  stream_.apiHandle = NULL;\r
-\r
-  for ( int i = 0; i < 2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  // update stream state\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-void RtApiWasapi::startStream( void )\r
-{\r
-  verifyStream();\r
-\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiWasapi::startStream: The stream is already running.";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // update stream state\r
-  stream_.state = STREAM_RUNNING;\r
-\r
-  // create WASAPI stream thread\r
-  stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );\r
-\r
-  if ( !stream_.callbackInfo.thread ) {\r
-    errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";\r
-    error( RtAudioError::THREAD_ERROR );\r
-  }\r
-  else {\r
-    SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );\r
-    ResumeThread( ( void* ) stream_.callbackInfo.thread );\r
-  }\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-void RtApiWasapi::stopStream( void )\r
-{\r
-  verifyStream();\r
-\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // inform stream thread by setting stream state to STREAM_STOPPING\r
-  stream_.state = STREAM_STOPPING;\r
-\r
-  // wait until stream thread is stopped\r
-  while( stream_.state != STREAM_STOPPED ) {\r
-    Sleep( 1 );\r
-  }\r
-\r
-  // Wait for the last buffer to play before stopping.\r
-  Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );\r
-\r
-  // stop capture client if applicable\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
-    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";\r
-      error( RtAudioError::DRIVER_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  // stop render client if applicable\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
-    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";\r
-      error( RtAudioError::DRIVER_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  // close thread handle\r
-  if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
-    errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";\r
-    error( RtAudioError::THREAD_ERROR );\r
-    return;\r
-  }\r
-\r
-  stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-void RtApiWasapi::abortStream( void )\r
-{\r
-  verifyStream();\r
-\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // inform stream thread by setting stream state to STREAM_STOPPING\r
-  stream_.state = STREAM_STOPPING;\r
-\r
-  // wait until stream thread is stopped\r
-  while ( stream_.state != STREAM_STOPPED ) {\r
-    Sleep( 1 );\r
-  }\r
-\r
-  // stop capture client if applicable\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
-    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";\r
-      error( RtAudioError::DRIVER_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  // stop render client if applicable\r
-  if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
-    HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";\r
-      error( RtAudioError::DRIVER_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  // close thread handle\r
-  if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
-    errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";\r
-    error( RtAudioError::THREAD_ERROR );\r
-    return;\r
-  }\r
-\r
-  stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                   unsigned int firstChannel, unsigned int sampleRate,\r
-                                   RtAudioFormat format, unsigned int* bufferSize,\r
-                                   RtAudio::StreamOptions* options )\r
-{\r
-  bool methodResult = FAILURE;\r
-  unsigned int captureDeviceCount = 0;\r
-  unsigned int renderDeviceCount = 0;\r
-\r
-  IMMDeviceCollection* captureDevices = NULL;\r
-  IMMDeviceCollection* renderDevices = NULL;\r
-  IMMDevice* devicePtr = NULL;\r
-  WAVEFORMATEX* deviceFormat = NULL;\r
-  unsigned int bufferBytes;\r
-  stream_.state = STREAM_STOPPED;\r
-\r
-  // create API Handle if not already created\r
-  if ( !stream_.apiHandle )\r
-    stream_.apiHandle = ( void* ) new WasapiHandle();\r
-\r
-  // Count capture devices\r
-  errorText_.clear();\r
-  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
-  HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = captureDevices->GetCount( &captureDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";\r
-    goto Exit;\r
-  }\r
-\r
-  // Count render devices\r
-  hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";\r
-    goto Exit;\r
-  }\r
-\r
-  hr = renderDevices->GetCount( &renderDeviceCount );\r
-  if ( FAILED( hr ) ) {\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";\r
-    goto Exit;\r
-  }\r
-\r
-  // validate device index\r
-  if ( device >= captureDeviceCount + renderDeviceCount ) {\r
-    errorType = RtAudioError::INVALID_USE;\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";\r
-    goto Exit;\r
-  }\r
-\r
-  // determine whether index falls within capture or render devices\r
-  if ( device >= renderDeviceCount ) {\r
-    if ( mode != INPUT ) {\r
-      errorType = RtAudioError::INVALID_USE;\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";\r
-      goto Exit;\r
-    }\r
-\r
-    // retrieve captureAudioClient from devicePtr\r
-    IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;\r
-\r
-    hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";\r
-      goto Exit;\r
-    }\r
-\r
-    hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
-                              NULL, ( void** ) &captureAudioClient );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
-      goto Exit;\r
-    }\r
-\r
-    hr = captureAudioClient->GetMixFormat( &deviceFormat );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
-      goto Exit;\r
-    }\r
-\r
-    stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
-    captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
-  }\r
-  else {\r
-    if ( mode != OUTPUT ) {\r
-      errorType = RtAudioError::INVALID_USE;\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";\r
-      goto Exit;\r
-    }\r
-\r
-    // retrieve renderAudioClient from devicePtr\r
-    IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;\r
-\r
-    hr = renderDevices->Item( device, &devicePtr );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";\r
-      goto Exit;\r
-    }\r
-\r
-    hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
-                              NULL, ( void** ) &renderAudioClient );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
-      goto Exit;\r
-    }\r
-\r
-    hr = renderAudioClient->GetMixFormat( &deviceFormat );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
-      goto Exit;\r
-    }\r
-\r
-    stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
-    renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
-  }\r
-\r
-  // fill stream data\r
-  if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||\r
-       ( stream_.mode == INPUT && mode == OUTPUT ) ) {\r
-    stream_.mode = DUPLEX;\r
-  }\r
-  else {\r
-    stream_.mode = mode;\r
-  }\r
-\r
-  stream_.device[mode] = device;\r
-  stream_.doByteSwap[mode] = false;\r
-  stream_.sampleRate = sampleRate;\r
-  stream_.bufferSize = *bufferSize;\r
-  stream_.nBuffers = 1;\r
-  stream_.nUserChannels[mode] = channels;\r
-  stream_.channelOffset[mode] = firstChannel;\r
-  stream_.userFormat = format;\r
-  stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;\r
-\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED )\r
-    stream_.userInterleaved = false;\r
-  else\r
-    stream_.userInterleaved = true;\r
-  stream_.deviceInterleaved[mode] = true;\r
-\r
-  // Set flags for buffer conversion.\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] ||\r
-       stream_.nUserChannels != stream_.nDeviceChannels )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-            stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  if ( stream_.doConvertBuffer[mode] )\r
-    setConvertInfo( mode, 0 );\r
-\r
-  // Allocate necessary internal buffers\r
-  bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
-\r
-  stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );\r
-  if ( !stream_.userBuffer[mode] ) {\r
-    errorType = RtAudioError::MEMORY_ERROR;\r
-    errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";\r
-    goto Exit;\r
-  }\r
-\r
-  if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )\r
-    stream_.callbackInfo.priority = 15;\r
-  else\r
-    stream_.callbackInfo.priority = 0;\r
-\r
-  ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback\r
-  ///! TODO: RTAUDIO_HOG_DEVICE       // Exclusive mode\r
-\r
-  methodResult = SUCCESS;\r
-\r
-Exit:\r
-  //clean up\r
-  SAFE_RELEASE( captureDevices );\r
-  SAFE_RELEASE( renderDevices );\r
-  SAFE_RELEASE( devicePtr );\r
-  CoTaskMemFree( deviceFormat );\r
-\r
-  // if method failed, close the stream\r
-  if ( methodResult == FAILURE )\r
-    closeStream();\r
-\r
-  if ( !errorText_.empty() )\r
-    error( errorType );\r
-  return methodResult;\r
-}\r
-\r
-//=============================================================================\r
-\r
-DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )\r
-{\r
-  if ( wasapiPtr )\r
-    ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();\r
-\r
-  return 0;\r
-}\r
-\r
-DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )\r
-{\r
-  if ( wasapiPtr )\r
-    ( ( RtApiWasapi* ) wasapiPtr )->stopStream();\r
-\r
-  return 0;\r
-}\r
-\r
-DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )\r
-{\r
-  if ( wasapiPtr )\r
-    ( ( RtApiWasapi* ) wasapiPtr )->abortStream();\r
-\r
-  return 0;\r
-}\r
-\r
-//-----------------------------------------------------------------------------\r
-\r
-void RtApiWasapi::wasapiThread()\r
-{\r
-  // as this is a new thread, we must CoInitialize it\r
-  CoInitialize( NULL );\r
-\r
-  HRESULT hr;\r
-\r
-  IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;\r
-  IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;\r
-  IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;\r
-  IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;\r
-  HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;\r
-  HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;\r
-\r
-  WAVEFORMATEX* captureFormat = NULL;\r
-  WAVEFORMATEX* renderFormat = NULL;\r
-  float captureSrRatio = 0.0f;\r
-  float renderSrRatio = 0.0f;\r
-  WasapiBuffer captureBuffer;\r
-  WasapiBuffer renderBuffer;\r
-\r
-  // declare local stream variables\r
-  RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;\r
-  BYTE* streamBuffer = NULL;\r
-  unsigned long captureFlags = 0;\r
-  unsigned int bufferFrameCount = 0;\r
-  unsigned int numFramesPadding = 0;\r
-  unsigned int convBufferSize = 0;\r
-  bool callbackPushed = false;\r
-  bool callbackPulled = false;\r
-  bool callbackStopped = false;\r
-  int callbackResult = 0;\r
-\r
-  // convBuffer is used to store converted buffers between WASAPI and the user\r
-  char* convBuffer = NULL;\r
-  unsigned int convBuffSize = 0;\r
-  unsigned int deviceBuffSize = 0;\r
-\r
-  errorText_.clear();\r
-  RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
-\r
-  // Attempt to assign "Pro Audio" characteristic to thread\r
-  HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );\r
-  if ( AvrtDll ) {\r
-    DWORD taskIndex = 0;\r
-    TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );\r
-    AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );\r
-    FreeLibrary( AvrtDll );\r
-  }\r
-\r
-  // start capture stream if applicable\r
-  if ( captureAudioClient ) {\r
-    hr = captureAudioClient->GetMixFormat( &captureFormat );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
-      goto Exit;\r
-    }\r
-\r
-    captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );\r
-\r
-    // initialize capture stream according to desire buffer size\r
-    float desiredBufferSize = stream_.bufferSize * captureSrRatio;\r
-    REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );\r
-\r
-    if ( !captureClient ) {\r
-      hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,\r
-                                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK,\r
-                                           desiredBufferPeriod,\r
-                                           desiredBufferPeriod,\r
-                                           captureFormat,\r
-                                           NULL );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";\r
-        goto Exit;\r
-      }\r
-\r
-      hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),\r
-                                           ( void** ) &captureClient );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";\r
-        goto Exit;\r
-      }\r
-\r
-      // configure captureEvent to trigger on every available capture buffer\r
-      captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
-      if ( !captureEvent ) {\r
-        errorType = RtAudioError::SYSTEM_ERROR;\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";\r
-        goto Exit;\r
-      }\r
-\r
-      hr = captureAudioClient->SetEventHandle( captureEvent );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";\r
-        goto Exit;\r
-      }\r
-\r
-      ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;\r
-      ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;\r
-    }\r
-\r
-    unsigned int inBufferSize = 0;\r
-    hr = captureAudioClient->GetBufferSize( &inBufferSize );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";\r
-      goto Exit;\r
-    }\r
-\r
-    // scale outBufferSize according to stream->user sample rate ratio\r
-    unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];\r
-    inBufferSize *= stream_.nDeviceChannels[INPUT];\r
-\r
-    // set captureBuffer size\r
-    captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );\r
-\r
-    // reset the capture stream\r
-    hr = captureAudioClient->Reset();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";\r
-      goto Exit;\r
-    }\r
-\r
-    // start the capture stream\r
-    hr = captureAudioClient->Start();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";\r
-      goto Exit;\r
-    }\r
-  }\r
-\r
-  // start render stream if applicable\r
-  if ( renderAudioClient ) {\r
-    hr = renderAudioClient->GetMixFormat( &renderFormat );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
-      goto Exit;\r
-    }\r
-\r
-    renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );\r
-\r
-    // initialize render stream according to desire buffer size\r
-    float desiredBufferSize = stream_.bufferSize * renderSrRatio;\r
-    REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );\r
-\r
-    if ( !renderClient ) {\r
-      hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,\r
-                                          AUDCLNT_STREAMFLAGS_EVENTCALLBACK,\r
-                                          desiredBufferPeriod,\r
-                                          desiredBufferPeriod,\r
-                                          renderFormat,\r
-                                          NULL );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";\r
-        goto Exit;\r
-      }\r
-\r
-      hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),\r
-                                          ( void** ) &renderClient );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";\r
-        goto Exit;\r
-      }\r
-\r
-      // configure renderEvent to trigger on every available render buffer\r
-      renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
-      if ( !renderEvent ) {\r
-        errorType = RtAudioError::SYSTEM_ERROR;\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";\r
-        goto Exit;\r
-      }\r
-\r
-      hr = renderAudioClient->SetEventHandle( renderEvent );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";\r
-        goto Exit;\r
-      }\r
-\r
-      ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;\r
-      ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;\r
-    }\r
-\r
-    unsigned int outBufferSize = 0;\r
-    hr = renderAudioClient->GetBufferSize( &outBufferSize );\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";\r
-      goto Exit;\r
-    }\r
-\r
-    // scale inBufferSize according to user->stream sample rate ratio\r
-    unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];\r
-    outBufferSize *= stream_.nDeviceChannels[OUTPUT];\r
-\r
-    // set renderBuffer size\r
-    renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
-\r
-    // reset the render stream\r
-    hr = renderAudioClient->Reset();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";\r
-      goto Exit;\r
-    }\r
-\r
-    // start the render stream\r
-    hr = renderAudioClient->Start();\r
-    if ( FAILED( hr ) ) {\r
-      errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";\r
-      goto Exit;\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT ) {\r
-    convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );\r
-    deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );\r
-  }\r
-  else if ( stream_.mode == OUTPUT ) {\r
-    convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );\r
-    deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );\r
-  }\r
-  else if ( stream_.mode == DUPLEX ) {\r
-    convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
-                             ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
-    deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
-                               stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
-  }\r
-\r
-  convBuffer = ( char* ) malloc( convBuffSize );\r
-  stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );\r
-  if ( !convBuffer || !stream_.deviceBuffer ) {\r
-    errorType = RtAudioError::MEMORY_ERROR;\r
-    errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";\r
-    goto Exit;\r
-  }\r
-\r
-  // stream process loop\r
-  while ( stream_.state != STREAM_STOPPING ) {\r
-    if ( !callbackPulled ) {\r
-      // Callback Input\r
-      // ==============\r
-      // 1. Pull callback buffer from inputBuffer\r
-      // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count\r
-      //                          Convert callback buffer to user format\r
-\r
-      if ( captureAudioClient ) {\r
-        // Pull callback buffer from inputBuffer\r
-        callbackPulled = captureBuffer.pullBuffer( convBuffer,\r
-                                                   ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],\r
-                                                   stream_.deviceFormat[INPUT] );\r
-\r
-        if ( callbackPulled ) {\r
-          // Convert callback buffer to user sample rate\r
-          convertBufferWasapi( stream_.deviceBuffer,\r
-                               convBuffer,\r
-                               stream_.nDeviceChannels[INPUT],\r
-                               captureFormat->nSamplesPerSec,\r
-                               stream_.sampleRate,\r
-                               ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),\r
-                               convBufferSize,\r
-                               stream_.deviceFormat[INPUT] );\r
-\r
-          if ( stream_.doConvertBuffer[INPUT] ) {\r
-            // Convert callback buffer to user format\r
-            convertBuffer( stream_.userBuffer[INPUT],\r
-                           stream_.deviceBuffer,\r
-                           stream_.convertInfo[INPUT] );\r
-          }\r
-          else {\r
-            // no further conversion, simple copy deviceBuffer to userBuffer\r
-            memcpy( stream_.userBuffer[INPUT],\r
-                    stream_.deviceBuffer,\r
-                    stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );\r
-          }\r
-        }\r
-      }\r
-      else {\r
-        // if there is no capture stream, set callbackPulled flag\r
-        callbackPulled = true;\r
-      }\r
-\r
-      // Execute Callback\r
-      // ================\r
-      // 1. Execute user callback method\r
-      // 2. Handle return value from callback\r
-\r
-      // if callback has not requested the stream to stop\r
-      if ( callbackPulled && !callbackStopped ) {\r
-        // Execute user callback method\r
-        callbackResult = callback( stream_.userBuffer[OUTPUT],\r
-                                   stream_.userBuffer[INPUT],\r
-                                   stream_.bufferSize,\r
-                                   getStreamTime(),\r
-                                   captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,\r
-                                   stream_.callbackInfo.userData );\r
-\r
-        // Handle return value from callback\r
-        if ( callbackResult == 1 ) {\r
-          // instantiate a thread to stop this thread\r
-          HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );\r
-          if ( !threadHandle ) {\r
-            errorType = RtAudioError::THREAD_ERROR;\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";\r
-            goto Exit;\r
-          }\r
-          else if ( !CloseHandle( threadHandle ) ) {\r
-            errorType = RtAudioError::THREAD_ERROR;\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";\r
-            goto Exit;\r
-          }\r
-\r
-          callbackStopped = true;\r
-        }\r
-        else if ( callbackResult == 2 ) {\r
-          // instantiate a thread to stop this thread\r
-          HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );\r
-          if ( !threadHandle ) {\r
-            errorType = RtAudioError::THREAD_ERROR;\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";\r
-            goto Exit;\r
-          }\r
-          else if ( !CloseHandle( threadHandle ) ) {\r
-            errorType = RtAudioError::THREAD_ERROR;\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";\r
-            goto Exit;\r
-          }\r
-\r
-          callbackStopped = true;\r
-        }\r
-      }\r
-    }\r
-\r
-    // Callback Output\r
-    // ===============\r
-    // 1. Convert callback buffer to stream format\r
-    // 2. Convert callback buffer to stream sample rate and channel count\r
-    // 3. Push callback buffer into outputBuffer\r
-\r
-    if ( renderAudioClient && callbackPulled ) {\r
-      if ( stream_.doConvertBuffer[OUTPUT] ) {\r
-        // Convert callback buffer to stream format\r
-        convertBuffer( stream_.deviceBuffer,\r
-                       stream_.userBuffer[OUTPUT],\r
-                       stream_.convertInfo[OUTPUT] );\r
-\r
-      }\r
-\r
-      // Convert callback buffer to stream sample rate\r
-      convertBufferWasapi( convBuffer,\r
-                           stream_.deviceBuffer,\r
-                           stream_.nDeviceChannels[OUTPUT],\r
-                           stream_.sampleRate,\r
-                           renderFormat->nSamplesPerSec,\r
-                           stream_.bufferSize,\r
-                           convBufferSize,\r
-                           stream_.deviceFormat[OUTPUT] );\r
-\r
-      // Push callback buffer into outputBuffer\r
-      callbackPushed = renderBuffer.pushBuffer( convBuffer,\r
-                                                convBufferSize * stream_.nDeviceChannels[OUTPUT],\r
-                                                stream_.deviceFormat[OUTPUT] );\r
-    }\r
-    else {\r
-      // if there is no render stream, set callbackPushed flag\r
-      callbackPushed = true;\r
-    }\r
-\r
-    // Stream Capture\r
-    // ==============\r
-    // 1. Get capture buffer from stream\r
-    // 2. Push capture buffer into inputBuffer\r
-    // 3. If 2. was successful: Release capture buffer\r
-\r
-    if ( captureAudioClient ) {\r
-      // if the callback input buffer was not pulled from captureBuffer, wait for next capture event\r
-      if ( !callbackPulled ) {\r
-        WaitForSingleObject( captureEvent, INFINITE );\r
-      }\r
-\r
-      // Get capture buffer from stream\r
-      hr = captureClient->GetBuffer( &streamBuffer,\r
-                                     &bufferFrameCount,\r
-                                     &captureFlags, NULL, NULL );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";\r
-        goto Exit;\r
-      }\r
-\r
-      if ( bufferFrameCount != 0 ) {\r
-        // Push capture buffer into inputBuffer\r
-        if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,\r
-                                       bufferFrameCount * stream_.nDeviceChannels[INPUT],\r
-                                       stream_.deviceFormat[INPUT] ) )\r
-        {\r
-          // Release capture buffer\r
-          hr = captureClient->ReleaseBuffer( bufferFrameCount );\r
-          if ( FAILED( hr ) ) {\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
-            goto Exit;\r
-          }\r
-        }\r
-        else\r
-        {\r
-          // Inform WASAPI that capture was unsuccessful\r
-          hr = captureClient->ReleaseBuffer( 0 );\r
-          if ( FAILED( hr ) ) {\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
-            goto Exit;\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // Inform WASAPI that capture was unsuccessful\r
-        hr = captureClient->ReleaseBuffer( 0 );\r
-        if ( FAILED( hr ) ) {\r
-          errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
-          goto Exit;\r
-        }\r
-      }\r
-    }\r
-\r
-    // Stream Render\r
-    // =============\r
-    // 1. Get render buffer from stream\r
-    // 2. Pull next buffer from outputBuffer\r
-    // 3. If 2. was successful: Fill render buffer with next buffer\r
-    //                          Release render buffer\r
-\r
-    if ( renderAudioClient ) {\r
-      // if the callback output buffer was not pushed to renderBuffer, wait for next render event\r
-      if ( callbackPulled && !callbackPushed ) {\r
-        WaitForSingleObject( renderEvent, INFINITE );\r
-      }\r
-\r
-      // Get render buffer from stream\r
-      hr = renderAudioClient->GetBufferSize( &bufferFrameCount );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";\r
-        goto Exit;\r
-      }\r
-\r
-      hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );\r
-      if ( FAILED( hr ) ) {\r
-        errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";\r
-        goto Exit;\r
-      }\r
-\r
-      bufferFrameCount -= numFramesPadding;\r
-\r
-      if ( bufferFrameCount != 0 ) {\r
-        hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );\r
-        if ( FAILED( hr ) ) {\r
-          errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";\r
-          goto Exit;\r
-        }\r
-\r
-        // Pull next buffer from outputBuffer\r
-        // Fill render buffer with next buffer\r
-        if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,\r
-                                      bufferFrameCount * stream_.nDeviceChannels[OUTPUT],\r
-                                      stream_.deviceFormat[OUTPUT] ) )\r
-        {\r
-          // Release render buffer\r
-          hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );\r
-          if ( FAILED( hr ) ) {\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
-            goto Exit;\r
-          }\r
-        }\r
-        else\r
-        {\r
-          // Inform WASAPI that render was unsuccessful\r
-          hr = renderClient->ReleaseBuffer( 0, 0 );\r
-          if ( FAILED( hr ) ) {\r
-            errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
-            goto Exit;\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // Inform WASAPI that render was unsuccessful\r
-        hr = renderClient->ReleaseBuffer( 0, 0 );\r
-        if ( FAILED( hr ) ) {\r
-          errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
-          goto Exit;\r
-        }\r
-      }\r
-    }\r
-\r
-    // if the callback buffer was pushed renderBuffer reset callbackPulled flag\r
-    if ( callbackPushed ) {\r
-      callbackPulled = false;\r
-    }\r
-\r
-    // tick stream time\r
-    RtApi::tickStreamTime();\r
-  }\r
-\r
-Exit:\r
-  // clean up\r
-  CoTaskMemFree( captureFormat );\r
-  CoTaskMemFree( renderFormat );\r
-\r
-  free ( convBuffer );\r
-\r
-  CoUninitialize();\r
-\r
-  // update stream state\r
-  stream_.state = STREAM_STOPPED;\r
-\r
-  if ( errorText_.empty() )\r
-    return;\r
-  else\r
-    error( errorType );\r
-}\r
-\r
-//******************** End of __WINDOWS_WASAPI__ *********************//\r
-#endif\r
-\r
-\r
-#if defined(__WINDOWS_DS__) // Windows DirectSound API\r
-\r
-// Modified by Robin Davies, October 2005\r
-// - Improvements to DirectX pointer chasing. \r
-// - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.\r
-// - Auto-call CoInitialize for DSOUND and ASIO platforms.\r
-// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007\r
-// Changed device query structure for RtAudio 4.0.7, January 2010\r
-\r
-#include <dsound.h>\r
-#include <assert.h>\r
-#include <algorithm>\r
-\r
-#if defined(__MINGW32__)\r
-  // missing from latest mingw winapi\r
-#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */\r
-#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */\r
-#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */\r
-#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */\r
-#endif\r
-\r
-#define MINIMUM_DEVICE_BUFFER_SIZE 32768\r
-\r
-#ifdef _MSC_VER // if Microsoft Visual C++\r
-#pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.\r
-#endif\r
-\r
-static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )\r
-{\r
-  if ( pointer > bufferSize ) pointer -= bufferSize;\r
-  if ( laterPointer < earlierPointer ) laterPointer += bufferSize;\r
-  if ( pointer < earlierPointer ) pointer += bufferSize;\r
-  return pointer >= earlierPointer && pointer < laterPointer;\r
-}\r
-\r
-// A structure to hold various information related to the DirectSound\r
-// API implementation.\r
-struct DsHandle {\r
-  unsigned int drainCounter; // Tracks callback counts when draining\r
-  bool internalDrain;        // Indicates if stop is initiated from callback or not.\r
-  void *id[2];\r
-  void *buffer[2];\r
-  bool xrun[2];\r
-  UINT bufferPointer[2];  \r
-  DWORD dsBufferSize[2];\r
-  DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.\r
-  HANDLE condition;\r
-\r
-  DsHandle()\r
-    :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }\r
-};\r
-\r
-// Declarations for utility functions, callbacks, and structures\r
-// specific to the DirectSound implementation.\r
-static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,\r
-                                          LPCTSTR description,\r
-                                          LPCTSTR module,\r
-                                          LPVOID lpContext );\r
-\r
-static const char* getErrorString( int code );\r
-\r
-static unsigned __stdcall callbackHandler( void *ptr );\r
-\r
-struct DsDevice {\r
-  LPGUID id[2];\r
-  bool validId[2];\r
-  bool found;\r
-  std::string name;\r
-\r
-  DsDevice()\r
-  : found(false) { validId[0] = false; validId[1] = false; }\r
-};\r
-\r
-struct DsProbeData {\r
-  bool isInput;\r
-  std::vector<struct DsDevice>* dsDevices;\r
-};\r
-\r
-RtApiDs :: RtApiDs()\r
-{\r
-  // Dsound will run both-threaded. If CoInitialize fails, then just\r
-  // accept whatever the mainline chose for a threading model.\r
-  coInitialized_ = false;\r
-  HRESULT hr = CoInitialize( NULL );\r
-  if ( !FAILED( hr ) ) coInitialized_ = true;\r
-}\r
-\r
-RtApiDs :: ~RtApiDs()\r
-{\r
-  if ( coInitialized_ ) CoUninitialize(); // balanced call.\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-}\r
-\r
-// The DirectSound default output is always the first device.\r
-unsigned int RtApiDs :: getDefaultOutputDevice( void )\r
-{\r
-  return 0;\r
-}\r
-\r
-// The DirectSound default input is always the first input device,\r
-// which is the first capture device enumerated.\r
-unsigned int RtApiDs :: getDefaultInputDevice( void )\r
-{\r
-  return 0;\r
-}\r
-\r
-unsigned int RtApiDs :: getDeviceCount( void )\r
-{\r
-  // Set query flag for previously found devices to false, so that we\r
-  // can check for any devices that have disappeared.\r
-  for ( unsigned int i=0; i<dsDevices.size(); i++ )\r
-    dsDevices[i].found = false;\r
-\r
-  // Query DirectSound devices.\r
-  struct DsProbeData probeInfo;\r
-  probeInfo.isInput = false;\r
-  probeInfo.dsDevices = &dsDevices;\r
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
-  if ( FAILED( result ) ) {\r
-    errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-  }\r
-\r
-  // Query DirectSoundCapture devices.\r
-  probeInfo.isInput = true;\r
-  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
-  if ( FAILED( result ) ) {\r
-    errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-  }\r
-\r
-  // Clean out any devices that may have disappeared.\r
-  std::vector< int > indices;\r
-  for ( unsigned int i=0; i<dsDevices.size(); i++ )\r
-    if ( dsDevices[i].found == false ) indices.push_back( i );\r
-  //unsigned int nErased = 0;\r
-  for ( unsigned int i=0; i<indices.size(); i++ )\r
-    dsDevices.erase( dsDevices.begin()+indices[i] );\r
-  //dsDevices.erase( dsDevices.begin()-nErased++ );\r
-\r
-  return static_cast<unsigned int>(dsDevices.size());\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  if ( dsDevices.size() == 0 ) {\r
-    // Force a query of all devices\r
-    getDeviceCount();\r
-    if ( dsDevices.size() == 0 ) {\r
-      errorText_ = "RtApiDs::getDeviceInfo: no devices found!";\r
-      error( RtAudioError::INVALID_USE );\r
-      return info;\r
-    }\r
-  }\r
-\r
-  if ( device >= dsDevices.size() ) {\r
-    errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  HRESULT result;\r
-  if ( dsDevices[ device ].validId[0] == false ) goto probeInput;\r
-\r
-  LPDIRECTSOUND output;\r
-  DSCAPS outCaps;\r
-  result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );\r
-  if ( FAILED( result ) ) {\r
-    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    goto probeInput;\r
-  }\r
-\r
-  outCaps.dwSize = sizeof( outCaps );\r
-  result = output->GetCaps( &outCaps );\r
-  if ( FAILED( result ) ) {\r
-    output->Release();\r
-    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    goto probeInput;\r
-  }\r
-\r
-  // Get output channel information.\r
-  info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;\r
-\r
-  // Get sample rate information.\r
-  info.sampleRates.clear();\r
-  for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-    if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&\r
-         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate )\r
-      info.sampleRates.push_back( SAMPLE_RATES[k] );\r
-  }\r
-\r
-  // Get format information.\r
-  if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;\r
-  if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;\r
-\r
-  output->Release();\r
-\r
-  if ( getDefaultOutputDevice() == device )\r
-    info.isDefaultOutput = true;\r
-\r
-  if ( dsDevices[ device ].validId[1] == false ) {\r
-    info.name = dsDevices[ device ].name;\r
-    info.probed = true;\r
-    return info;\r
-  }\r
-\r
- probeInput:\r
-\r
-  LPDIRECTSOUNDCAPTURE input;\r
-  result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );\r
-  if ( FAILED( result ) ) {\r
-    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  DSCCAPS inCaps;\r
-  inCaps.dwSize = sizeof( inCaps );\r
-  result = input->GetCaps( &inCaps );\r
-  if ( FAILED( result ) ) {\r
-    input->Release();\r
-    errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Get input channel information.\r
-  info.inputChannels = inCaps.dwChannels;\r
-\r
-  // Get sample rate and format information.\r
-  std::vector<unsigned int> rates;\r
-  if ( inCaps.dwChannels >= 2 ) {\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-\r
-    if ( info.nativeFormats & RTAUDIO_SINT16 ) {\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );\r
-    }\r
-    else if ( info.nativeFormats & RTAUDIO_SINT8 ) {\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );\r
-    }\r
-  }\r
-  else if ( inCaps.dwChannels == 1 ) {\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-    if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;\r
-\r
-    if ( info.nativeFormats & RTAUDIO_SINT16 ) {\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );\r
-    }\r
-    else if ( info.nativeFormats & RTAUDIO_SINT8 ) {\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );\r
-      if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );\r
-    }\r
-  }\r
-  else info.inputChannels = 0; // technically, this would be an error\r
-\r
-  input->Release();\r
-\r
-  if ( info.inputChannels == 0 ) return info;\r
-\r
-  // Copy the supported rates to the info structure but avoid duplication.\r
-  bool found;\r
-  for ( unsigned int i=0; i<rates.size(); i++ ) {\r
-    found = false;\r
-    for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {\r
-      if ( rates[i] == info.sampleRates[j] ) {\r
-        found = true;\r
-        break;\r
-      }\r
-    }\r
-    if ( found == false ) info.sampleRates.push_back( rates[i] );\r
-  }\r
-  std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
-\r
-  // If device opens for both playback and capture, we determine the channels.\r
-  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
-    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-\r
-  if ( device == 0 ) info.isDefaultInput = true;\r
-\r
-  // Copy name and return.\r
-  info.name = dsDevices[ device ].name;\r
-  info.probed = true;\r
-  return info;\r
-}\r
-\r
-bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                 unsigned int firstChannel, unsigned int sampleRate,\r
-                                 RtAudioFormat format, unsigned int *bufferSize,\r
-                                 RtAudio::StreamOptions *options )\r
-{\r
-  if ( channels + firstChannel > 2 ) {\r
-    errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";\r
-    return FAILURE;\r
-  }\r
-\r
-  size_t nDevices = dsDevices.size();\r
-  if ( nDevices == 0 ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( mode == OUTPUT ) {\r
-    if ( dsDevices[ device ].validId[0] == false ) {\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-  else { // mode == INPUT\r
-    if ( dsDevices[ device ].validId[1] == false ) {\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // According to a note in PortAudio, using GetDesktopWindow()\r
-  // instead of GetForegroundWindow() is supposed to avoid problems\r
-  // that occur when the application's window is not the foreground\r
-  // window.  Also, if the application window closes before the\r
-  // DirectSound buffer, DirectSound can crash.  In the past, I had\r
-  // problems when using GetDesktopWindow() but it seems fine now\r
-  // (January 2010).  I'll leave it commented here.\r
-  // HWND hWnd = GetForegroundWindow();\r
-  HWND hWnd = GetDesktopWindow();\r
-\r
-  // Check the numberOfBuffers parameter and limit the lowest value to\r
-  // two.  This is a judgement call and a value of two is probably too\r
-  // low for capture, but it should work for playback.\r
-  int nBuffers = 0;\r
-  if ( options ) nBuffers = options->numberOfBuffers;\r
-  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;\r
-  if ( nBuffers < 2 ) nBuffers = 3;\r
-\r
-  // Check the lower range of the user-specified buffer size and set\r
-  // (arbitrarily) to a lower bound of 32.\r
-  if ( *bufferSize < 32 ) *bufferSize = 32;\r
-\r
-  // Create the wave format structure.  The data format setting will\r
-  // be determined later.\r
-  WAVEFORMATEX waveFormat;\r
-  ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );\r
-  waveFormat.wFormatTag = WAVE_FORMAT_PCM;\r
-  waveFormat.nChannels = channels + firstChannel;\r
-  waveFormat.nSamplesPerSec = (unsigned long) sampleRate;\r
-\r
-  // Determine the device buffer size. By default, we'll use the value\r
-  // defined above (32K), but we will grow it to make allowances for\r
-  // very large software buffer sizes.\r
-  DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;\r
-  DWORD dsPointerLeadTime = 0;\r
-\r
-  void *ohandle = 0, *bhandle = 0;\r
-  HRESULT result;\r
-  if ( mode == OUTPUT ) {\r
-\r
-    LPDIRECTSOUND output;\r
-    result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    DSCAPS outCaps;\r
-    outCaps.dwSize = sizeof( outCaps );\r
-    result = output->GetCaps( &outCaps );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Check channel information.\r
-    if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {\r
-      errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Check format information.  Use 16-bit format unless not\r
-    // supported or user requests 8-bit.\r
-    if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&\r
-         !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {\r
-      waveFormat.wBitsPerSample = 16;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-    }\r
-    else {\r
-      waveFormat.wBitsPerSample = 8;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-    }\r
-    stream_.userFormat = format;\r
-\r
-    // Update wave format structure and buffer information.\r
-    waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;\r
-    waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;\r
-    dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;\r
-\r
-    // If the user wants an even bigger buffer, increase the device buffer size accordingly.\r
-    while ( dsPointerLeadTime * 2U > dsBufferSize )\r
-      dsBufferSize *= 2;\r
-\r
-    // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.\r
-    // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );\r
-    // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.\r
-    result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Even though we will write to the secondary buffer, we need to\r
-    // access the primary buffer to set the correct output format\r
-    // (since the default is 8-bit, 22 kHz!).  Setup the DS primary\r
-    // buffer description.\r
-    DSBUFFERDESC bufferDescription;\r
-    ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );\r
-    bufferDescription.dwSize = sizeof( DSBUFFERDESC );\r
-    bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;\r
-\r
-    // Obtain the primary buffer\r
-    LPDIRECTSOUNDBUFFER buffer;\r
-    result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Set the primary DS buffer sound format.\r
-    result = buffer->SetFormat( &waveFormat );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Setup the secondary DS buffer description.\r
-    ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );\r
-    bufferDescription.dwSize = sizeof( DSBUFFERDESC );\r
-    bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |\r
-                                  DSBCAPS_GLOBALFOCUS |\r
-                                  DSBCAPS_GETCURRENTPOSITION2 |\r
-                                  DSBCAPS_LOCHARDWARE );  // Force hardware mixing\r
-    bufferDescription.dwBufferBytes = dsBufferSize;\r
-    bufferDescription.lpwfxFormat = &waveFormat;\r
-\r
-    // Try to create the secondary DS buffer.  If that doesn't work,\r
-    // try to use software mixing.  Otherwise, there's a problem.\r
-    result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
-    if ( FAILED( result ) ) {\r
-      bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |\r
-                                    DSBCAPS_GLOBALFOCUS |\r
-                                    DSBCAPS_GETCURRENTPOSITION2 |\r
-                                    DSBCAPS_LOCSOFTWARE );  // Force software mixing\r
-      result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );\r
-      if ( FAILED( result ) ) {\r
-        output->Release();\r
-        errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";\r
-        errorText_ = errorStream_.str();\r
-        return FAILURE;\r
-      }\r
-    }\r
-\r
-    // Get the buffer size ... might be different from what we specified.\r
-    DSBCAPS dsbcaps;\r
-    dsbcaps.dwSize = sizeof( DSBCAPS );\r
-    result = buffer->GetCaps( &dsbcaps );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    dsBufferSize = dsbcaps.dwBufferBytes;\r
-\r
-    // Lock the DS buffer\r
-    LPVOID audioPtr;\r
-    DWORD dataLen;\r
-    result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Zero the DS buffer\r
-    ZeroMemory( audioPtr, dataLen );\r
-\r
-    // Unlock the DS buffer\r
-    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      output->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    ohandle = (void *) output;\r
-    bhandle = (void *) buffer;\r
-  }\r
-\r
-  if ( mode == INPUT ) {\r
-\r
-    LPDIRECTSOUNDCAPTURE input;\r
-    result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    DSCCAPS inCaps;\r
-    inCaps.dwSize = sizeof( inCaps );\r
-    result = input->GetCaps( &inCaps );\r
-    if ( FAILED( result ) ) {\r
-      input->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Check channel information.\r
-    if ( inCaps.dwChannels < channels + firstChannel ) {\r
-      errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";\r
-      return FAILURE;\r
-    }\r
-\r
-    // Check format information.  Use 16-bit format unless user\r
-    // requests 8-bit.\r
-    DWORD deviceFormats;\r
-    if ( channels + firstChannel == 2 ) {\r
-      deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;\r
-      if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {\r
-        waveFormat.wBitsPerSample = 8;\r
-        stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-      }\r
-      else { // assume 16-bit is supported\r
-        waveFormat.wBitsPerSample = 16;\r
-        stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-      }\r
-    }\r
-    else { // channel == 1\r
-      deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;\r
-      if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {\r
-        waveFormat.wBitsPerSample = 8;\r
-        stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-      }\r
-      else { // assume 16-bit is supported\r
-        waveFormat.wBitsPerSample = 16;\r
-        stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-      }\r
-    }\r
-    stream_.userFormat = format;\r
-\r
-    // Update wave format structure and buffer information.\r
-    waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;\r
-    waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;\r
-    dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;\r
-\r
-    // If the user wants an even bigger buffer, increase the device buffer size accordingly.\r
-    while ( dsPointerLeadTime * 2U > dsBufferSize )\r
-      dsBufferSize *= 2;\r
-\r
-    // Setup the secondary DS buffer description.\r
-    DSCBUFFERDESC bufferDescription;\r
-    ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );\r
-    bufferDescription.dwSize = sizeof( DSCBUFFERDESC );\r
-    bufferDescription.dwFlags = 0;\r
-    bufferDescription.dwReserved = 0;\r
-    bufferDescription.dwBufferBytes = dsBufferSize;\r
-    bufferDescription.lpwfxFormat = &waveFormat;\r
-\r
-    // Create the capture buffer.\r
-    LPDIRECTSOUNDCAPTUREBUFFER buffer;\r
-    result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );\r
-    if ( FAILED( result ) ) {\r
-      input->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Get the buffer size ... might be different from what we specified.\r
-    DSCBCAPS dscbcaps;\r
-    dscbcaps.dwSize = sizeof( DSCBCAPS );\r
-    result = buffer->GetCaps( &dscbcaps );\r
-    if ( FAILED( result ) ) {\r
-      input->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    dsBufferSize = dscbcaps.dwBufferBytes;\r
-\r
-    // NOTE: We could have a problem here if this is a duplex stream\r
-    // and the play and capture hardware buffer sizes are different\r
-    // (I'm actually not sure if that is a problem or not).\r
-    // Currently, we are not verifying that.\r
-\r
-    // Lock the capture buffer\r
-    LPVOID audioPtr;\r
-    DWORD dataLen;\r
-    result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      input->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    // Zero the buffer\r
-    ZeroMemory( audioPtr, dataLen );\r
-\r
-    // Unlock the buffer\r
-    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      input->Release();\r
-      buffer->Release();\r
-      errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-\r
-    ohandle = (void *) input;\r
-    bhandle = (void *) buffer;\r
-  }\r
-\r
-  // Set various stream parameters\r
-  DsHandle *handle = 0;\r
-  stream_.nDeviceChannels[mode] = channels + firstChannel;\r
-  stream_.nUserChannels[mode] = channels;\r
-  stream_.bufferSize = *bufferSize;\r
-  stream_.channelOffset[mode] = firstChannel;\r
-  stream_.deviceInterleaved[mode] = true;\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
-  else stream_.userInterleaved = true;\r
-\r
-  // Set flag for buffer conversion\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if (stream_.userFormat != stream_.deviceFormat[mode])\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-       stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate necessary internal buffers\r
-  long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  // Allocate our DsHandle structures for the stream.\r
-  if ( stream_.apiHandle == 0 ) {\r
-    try {\r
-      handle = new DsHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";\r
-      goto error;\r
-    }\r
-\r
-    // Create a manual-reset event.\r
-    handle->condition = CreateEvent( NULL,   // no security\r
-                                     TRUE,   // manual-reset\r
-                                     FALSE,  // non-signaled initially\r
-                                     NULL ); // unnamed\r
-    stream_.apiHandle = (void *) handle;\r
-  }\r
-  else\r
-    handle = (DsHandle *) stream_.apiHandle;\r
-  handle->id[mode] = ohandle;\r
-  handle->buffer[mode] = bhandle;\r
-  handle->dsBufferSize[mode] = dsBufferSize;\r
-  handle->dsPointerLeadTime[mode] = dsPointerLeadTime;\r
-\r
-  stream_.device[mode] = device;\r
-  stream_.state = STREAM_STOPPED;\r
-  if ( stream_.mode == OUTPUT && mode == INPUT )\r
-    // We had already set up an output stream.\r
-    stream_.mode = DUPLEX;\r
-  else\r
-    stream_.mode = mode;\r
-  stream_.nBuffers = nBuffers;\r
-  stream_.sampleRate = sampleRate;\r
-\r
-  // Setup the buffer conversion information structure.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
-\r
-  // Setup the callback thread.\r
-  if ( stream_.callbackInfo.isRunning == false ) {\r
-    unsigned threadId;\r
-    stream_.callbackInfo.isRunning = true;\r
-    stream_.callbackInfo.object = (void *) this;\r
-    stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,\r
-                                                  &stream_.callbackInfo, 0, &threadId );\r
-    if ( stream_.callbackInfo.thread == 0 ) {\r
-      errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";\r
-      goto error;\r
-    }\r
-\r
-    // Boost DS thread priority\r
-    SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );\r
-  }\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( handle ) {\r
-    if ( handle->buffer[0] ) { // the object pointer can be NULL and valid\r
-      LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];\r
-      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-      if ( buffer ) buffer->Release();\r
-      object->Release();\r
-    }\r
-    if ( handle->buffer[1] ) {\r
-      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];\r
-      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-      if ( buffer ) buffer->Release();\r
-      object->Release();\r
-    }\r
-    CloseHandle( handle->condition );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.state = STREAM_CLOSED;\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiDs :: closeStream()\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiDs::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // Stop the callback thread.\r
-  stream_.callbackInfo.isRunning = false;\r
-  WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );\r
-  CloseHandle( (HANDLE) stream_.callbackInfo.thread );\r
-\r
-  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
-  if ( handle ) {\r
-    if ( handle->buffer[0] ) { // the object pointer can be NULL and valid\r
-      LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];\r
-      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-      if ( buffer ) {\r
-        buffer->Stop();\r
-        buffer->Release();\r
-      }\r
-      object->Release();\r
-    }\r
-    if ( handle->buffer[1] ) {\r
-      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];\r
-      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-      if ( buffer ) {\r
-        buffer->Stop();\r
-        buffer->Release();\r
-      }\r
-      object->Release();\r
-    }\r
-    CloseHandle( handle->condition );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-void RtApiDs :: startStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiDs::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
-\r
-  // Increase scheduler frequency on lesser windows (a side-effect of\r
-  // increasing timer accuracy).  On greater windows (Win2K or later),\r
-  // this is already in effect.\r
-  timeBeginPeriod( 1 ); \r
-\r
-  buffersRolling = false;\r
-  duplexPrerollBytes = 0;\r
-\r
-  if ( stream_.mode == DUPLEX ) {\r
-    // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.\r
-    duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );\r
-  }\r
-\r
-  HRESULT result = 0;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-    result = buffer->Play( 0, 0, DSBPLAY_LOOPING );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-    result = buffer->Start( DSCBSTART_LOOPING );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  handle->drainCounter = 0;\r
-  handle->internalDrain = false;\r
-  ResetEvent( handle->condition );\r
-  stream_.state = STREAM_RUNNING;\r
-\r
- unlock:\r
-  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiDs :: stopStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  HRESULT result = 0;\r
-  LPVOID audioPtr;\r
-  DWORD dataLen;\r
-  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    if ( handle->drainCounter == 0 ) {\r
-      handle->drainCounter = 2;\r
-      WaitForSingleObject( handle->condition, INFINITE );  // block until signaled\r
-    }\r
-\r
-    stream_.state = STREAM_STOPPED;\r
-\r
-    MUTEX_LOCK( &stream_.mutex );\r
-\r
-    // Stop the buffer and clear memory\r
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-    result = buffer->Stop();\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // Lock the buffer and clear it so that if we start to play again,\r
-    // we won't have old data playing.\r
-    result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // Zero the DS buffer\r
-    ZeroMemory( audioPtr, dataLen );\r
-\r
-    // Unlock the DS buffer\r
-    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // If we start playing again, we must begin at beginning of buffer.\r
-    handle->bufferPointer[0] = 0;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-    audioPtr = NULL;\r
-    dataLen = 0;\r
-\r
-    stream_.state = STREAM_STOPPED;\r
-\r
-    if ( stream_.mode != DUPLEX )\r
-      MUTEX_LOCK( &stream_.mutex );\r
-\r
-    result = buffer->Stop();\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // Lock the buffer and clear it so that if we start to play again,\r
-    // we won't have old data playing.\r
-    result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // Zero the DS buffer\r
-    ZeroMemory( audioPtr, dataLen );\r
-\r
-    // Unlock the DS buffer\r
-    result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-\r
-    // If we start recording again, we must begin at beginning of buffer.\r
-    handle->bufferPointer[1] = 0;\r
-  }\r
-\r
- unlock:\r
-  timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiDs :: abortStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
-  handle->drainCounter = 2;\r
-\r
-  stopStream();\r
-}\r
-\r
-void RtApiDs :: callbackEvent()\r
-{\r
-  if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {\r
-    Sleep( 50 ); // sleep 50 milliseconds\r
-    return;\r
-  }\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;\r
-  DsHandle *handle = (DsHandle *) stream_.apiHandle;\r
-\r
-  // Check if we were draining the stream and signal is finished.\r
-  if ( handle->drainCounter > stream_.nBuffers + 2 ) {\r
-\r
-    stream_.state = STREAM_STOPPING;\r
-    if ( handle->internalDrain == false )\r
-      SetEvent( handle->condition );\r
-    else\r
-      stopStream();\r
-    return;\r
-  }\r
-\r
-  // Invoke user callback to get fresh output data UNLESS we are\r
-  // draining stream.\r
-  if ( handle->drainCounter == 0 ) {\r
-    RtAudioCallback callback = (RtAudioCallback) info->callback;\r
-    double streamTime = getStreamTime();\r
-    RtAudioStreamStatus status = 0;\r
-    if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
-      status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-      handle->xrun[0] = false;\r
-    }\r
-    if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
-      status |= RTAUDIO_INPUT_OVERFLOW;\r
-      handle->xrun[1] = false;\r
-    }\r
-    int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                                  stream_.bufferSize, streamTime, status, info->userData );\r
-    if ( cbReturnValue == 2 ) {\r
-      stream_.state = STREAM_STOPPING;\r
-      handle->drainCounter = 2;\r
-      abortStream();\r
-      return;\r
-    }\r
-    else if ( cbReturnValue == 1 ) {\r
-      handle->drainCounter = 1;\r
-      handle->internalDrain = true;\r
-    }\r
-  }\r
-\r
-  HRESULT result;\r
-  DWORD currentWritePointer, safeWritePointer;\r
-  DWORD currentReadPointer, safeReadPointer;\r
-  UINT nextWritePointer;\r
-\r
-  LPVOID buffer1 = NULL;\r
-  LPVOID buffer2 = NULL;\r
-  DWORD bufferSize1 = 0;\r
-  DWORD bufferSize2 = 0;\r
-\r
-  char *buffer;\r
-  long bufferBytes;\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-    return;\r
-  }\r
-\r
-  if ( buffersRolling == false ) {\r
-    if ( stream_.mode == DUPLEX ) {\r
-      //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );\r
-\r
-      // It takes a while for the devices to get rolling. As a result,\r
-      // there's no guarantee that the capture and write device pointers\r
-      // will move in lockstep.  Wait here for both devices to start\r
-      // rolling, and then set our buffer pointers accordingly.\r
-      // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600\r
-      // bytes later than the write buffer.\r
-\r
-      // Stub: a serious risk of having a pre-emptive scheduling round\r
-      // take place between the two GetCurrentPosition calls... but I'm\r
-      // really not sure how to solve the problem.  Temporarily boost to\r
-      // Realtime priority, maybe; but I'm not sure what priority the\r
-      // DirectSound service threads run at. We *should* be roughly\r
-      // within a ms or so of correct.\r
-\r
-      LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-      LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-\r
-      DWORD startSafeWritePointer, startSafeReadPointer;\r
-\r
-      result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );\r
-      if ( FAILED( result ) ) {\r
-        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::SYSTEM_ERROR );\r
-        return;\r
-      }\r
-      result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );\r
-      if ( FAILED( result ) ) {\r
-        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::SYSTEM_ERROR );\r
-        return;\r
-      }\r
-      while ( true ) {\r
-        result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );\r
-        if ( FAILED( result ) ) {\r
-          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
-          errorText_ = errorStream_.str();\r
-          error( RtAudioError::SYSTEM_ERROR );\r
-          return;\r
-        }\r
-        result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );\r
-        if ( FAILED( result ) ) {\r
-          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
-          errorText_ = errorStream_.str();\r
-          error( RtAudioError::SYSTEM_ERROR );\r
-          return;\r
-        }\r
-        if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;\r
-        Sleep( 1 );\r
-      }\r
-\r
-      //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );\r
-\r
-      handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
-      if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
-      handle->bufferPointer[1] = safeReadPointer;\r
-    }\r
-    else if ( stream_.mode == OUTPUT ) {\r
-\r
-      // Set the proper nextWritePosition after initial startup.\r
-      LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-      result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );\r
-      if ( FAILED( result ) ) {\r
-        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::SYSTEM_ERROR );\r
-        return;\r
-      }\r
-      handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
-      if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
-    }\r
-\r
-    buffersRolling = true;\r
-  }\r
-\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    \r
-    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
-\r
-    if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
-      bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];\r
-      bufferBytes *= formatBytes( stream_.userFormat );\r
-      memset( stream_.userBuffer[0], 0, bufferBytes );\r
-    }\r
-\r
-    // Setup parameters and do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[0] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-      bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];\r
-      bufferBytes *= formatBytes( stream_.deviceFormat[0] );\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[0];\r
-      bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];\r
-      bufferBytes *= formatBytes( stream_.userFormat );\r
-    }\r
-\r
-    // No byte swapping necessary in DirectSound implementation.\r
-\r
-    // Ahhh ... windoze.  16-bit data is signed but 8-bit data is\r
-    // unsigned.  So, we need to convert our signed 8-bit data here to\r
-    // unsigned.\r
-    if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )\r
-      for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );\r
-\r
-    DWORD dsBufferSize = handle->dsBufferSize[0];\r
-    nextWritePointer = handle->bufferPointer[0];\r
-\r
-    DWORD endWrite, leadPointer;\r
-    while ( true ) {\r
-      // Find out where the read and "safe write" pointers are.\r
-      result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );\r
-      if ( FAILED( result ) ) {\r
-        errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::SYSTEM_ERROR );\r
-        return;\r
-      }\r
-\r
-      // We will copy our output buffer into the region between\r
-      // safeWritePointer and leadPointer.  If leadPointer is not\r
-      // beyond the next endWrite position, wait until it is.\r
-      leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];\r
-      //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;\r
-      if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;\r
-      if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset\r
-      endWrite = nextWritePointer + bufferBytes;\r
-\r
-      // Check whether the entire write region is behind the play pointer.\r
-      if ( leadPointer >= endWrite ) break;\r
-\r
-      // If we are here, then we must wait until the leadPointer advances\r
-      // beyond the end of our next write region. We use the\r
-      // Sleep() function to suspend operation until that happens.\r
-      double millis = ( endWrite - leadPointer ) * 1000.0;\r
-      millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);\r
-      if ( millis < 1.0 ) millis = 1.0;\r
-      Sleep( (DWORD) millis );\r
-    }\r
-\r
-    if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )\r
-         || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { \r
-      // We've strayed into the forbidden zone ... resync the read pointer.\r
-      handle->xrun[0] = true;\r
-      nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;\r
-      if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;\r
-      handle->bufferPointer[0] = nextWritePointer;\r
-      endWrite = nextWritePointer + bufferBytes;\r
-    }\r
-\r
-    // Lock free space in the buffer\r
-    result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,\r
-                             &bufferSize1, &buffer2, &bufferSize2, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-\r
-    // Copy our buffer into the DS buffer\r
-    CopyMemory( buffer1, buffer, bufferSize1 );\r
-    if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );\r
-\r
-    // Update our buffer offset and unlock sound buffer\r
-    dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-    nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
-    handle->bufferPointer[0] = nextWritePointer;\r
-  }\r
-\r
-  // Don't bother draining input\r
-  if ( handle->drainCounter ) {\r
-    handle->drainCounter++;\r
-    goto unlock;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Setup parameters.\r
-    if ( stream_.doConvertBuffer[1] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];\r
-      bufferBytes *= formatBytes( stream_.deviceFormat[1] );\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[1];\r
-      bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];\r
-      bufferBytes *= formatBytes( stream_.userFormat );\r
-    }\r
-\r
-    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];\r
-    long nextReadPointer = handle->bufferPointer[1];\r
-    DWORD dsBufferSize = handle->dsBufferSize[1];\r
-\r
-    // Find out where the write and "safe read" pointers are.\r
-    result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-\r
-    if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
-    DWORD endRead = nextReadPointer + bufferBytes;\r
-\r
-    // Handling depends on whether we are INPUT or DUPLEX. \r
-    // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,\r
-    // then a wait here will drag the write pointers into the forbidden zone.\r
-    // \r
-    // In DUPLEX mode, rather than wait, we will back off the read pointer until \r
-    // it's in a safe position. This causes dropouts, but it seems to be the only \r
-    // practical way to sync up the read and write pointers reliably, given the \r
-    // the very complex relationship between phase and increment of the read and write \r
-    // pointers.\r
-    //\r
-    // In order to minimize audible dropouts in DUPLEX mode, we will\r
-    // provide a pre-roll period of 0.5 seconds in which we return\r
-    // zeros from the read buffer while the pointers sync up.\r
-\r
-    if ( stream_.mode == DUPLEX ) {\r
-      if ( safeReadPointer < endRead ) {\r
-        if ( duplexPrerollBytes <= 0 ) {\r
-          // Pre-roll time over. Be more agressive.\r
-          int adjustment = endRead-safeReadPointer;\r
-\r
-          handle->xrun[1] = true;\r
-          // Two cases:\r
-          //   - large adjustments: we've probably run out of CPU cycles, so just resync exactly,\r
-          //     and perform fine adjustments later.\r
-          //   - small adjustments: back off by twice as much.\r
-          if ( adjustment >= 2*bufferBytes )\r
-            nextReadPointer = safeReadPointer-2*bufferBytes;\r
-          else\r
-            nextReadPointer = safeReadPointer-bufferBytes-adjustment;\r
-\r
-          if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;\r
-\r
-        }\r
-        else {\r
-          // In pre=roll time. Just do it.\r
-          nextReadPointer = safeReadPointer - bufferBytes;\r
-          while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;\r
-        }\r
-        endRead = nextReadPointer + bufferBytes;\r
-      }\r
-    }\r
-    else { // mode == INPUT\r
-      while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {\r
-        // See comments for playback.\r
-        double millis = (endRead - safeReadPointer) * 1000.0;\r
-        millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);\r
-        if ( millis < 1.0 ) millis = 1.0;\r
-        Sleep( (DWORD) millis );\r
-\r
-        // Wake up and find out where we are now.\r
-        result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );\r
-        if ( FAILED( result ) ) {\r
-          errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
-          errorText_ = errorStream_.str();\r
-          error( RtAudioError::SYSTEM_ERROR );\r
-          return;\r
-        }\r
-      \r
-        if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
-      }\r
-    }\r
-\r
-    // Lock free space in the buffer\r
-    result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,\r
-                             &bufferSize1, &buffer2, &bufferSize2, 0 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-\r
-    if ( duplexPrerollBytes <= 0 ) {\r
-      // Copy our buffer into the DS buffer\r
-      CopyMemory( buffer, buffer1, bufferSize1 );\r
-      if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );\r
-    }\r
-    else {\r
-      memset( buffer, 0, bufferSize1 );\r
-      if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );\r
-      duplexPrerollBytes -= bufferSize1 + bufferSize2;\r
-    }\r
-\r
-    // Update our buffer offset and unlock sound buffer\r
-    nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
-    dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );\r
-    if ( FAILED( result ) ) {\r
-      errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-    handle->bufferPointer[1] = nextReadPointer;\r
-\r
-    // No byte swapping necessary in DirectSound implementation.\r
-\r
-    // If necessary, convert 8-bit data from unsigned to signed.\r
-    if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )\r
-      for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );\r
-\r
-    // Do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[1] )\r
-      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
-  }\r
-\r
- unlock:\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-  RtApi::tickStreamTime();\r
-}\r
-\r
-// Definitions for utility functions and callbacks\r
-// specific to the DirectSound implementation.\r
-\r
-static unsigned __stdcall callbackHandler( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiDs *object = (RtApiDs *) info->object;\r
-  bool* isRunning = &info->isRunning;\r
-\r
-  while ( *isRunning == true ) {\r
-    object->callbackEvent();\r
-  }\r
-\r
-  _endthreadex( 0 );\r
-  return 0;\r
-}\r
-\r
-#include "tchar.h"\r
-\r
-static std::string convertTChar( LPCTSTR name )\r
-{\r
-#if defined( UNICODE ) || defined( _UNICODE )\r
-  int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);\r
-  std::string s( length-1, '\0' );\r
-  WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);\r
-#else\r
-  std::string s( name );\r
-#endif\r
-\r
-  return s;\r
-}\r
-\r
-static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,\r
-                                          LPCTSTR description,\r
-                                          LPCTSTR /*module*/,\r
-                                          LPVOID lpContext )\r
-{\r
-  struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;\r
-  std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;\r
-\r
-  HRESULT hr;\r
-  bool validDevice = false;\r
-  if ( probeInfo.isInput == true ) {\r
-    DSCCAPS caps;\r
-    LPDIRECTSOUNDCAPTURE object;\r
-\r
-    hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );\r
-    if ( hr != DS_OK ) return TRUE;\r
-\r
-    caps.dwSize = sizeof(caps);\r
-    hr = object->GetCaps( &caps );\r
-    if ( hr == DS_OK ) {\r
-      if ( caps.dwChannels > 0 && caps.dwFormats > 0 )\r
-        validDevice = true;\r
-    }\r
-    object->Release();\r
-  }\r
-  else {\r
-    DSCAPS caps;\r
-    LPDIRECTSOUND object;\r
-    hr = DirectSoundCreate(  lpguid, &object,   NULL );\r
-    if ( hr != DS_OK ) return TRUE;\r
-\r
-    caps.dwSize = sizeof(caps);\r
-    hr = object->GetCaps( &caps );\r
-    if ( hr == DS_OK ) {\r
-      if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )\r
-        validDevice = true;\r
-    }\r
-    object->Release();\r
-  }\r
-\r
-  // If good device, then save its name and guid.\r
-  std::string name = convertTChar( description );\r
-  //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
-  if ( lpguid == NULL )\r
-    name = "Default Device";\r
-  if ( validDevice ) {\r
-    for ( unsigned int i=0; i<dsDevices.size(); i++ ) {\r
-      if ( dsDevices[i].name == name ) {\r
-        dsDevices[i].found = true;\r
-        if ( probeInfo.isInput ) {\r
-          dsDevices[i].id[1] = lpguid;\r
-          dsDevices[i].validId[1] = true;\r
-        }\r
-        else {\r
-          dsDevices[i].id[0] = lpguid;\r
-          dsDevices[i].validId[0] = true;\r
-        }\r
-        return TRUE;\r
-      }\r
-    }\r
-\r
-    DsDevice device;\r
-    device.name = name;\r
-    device.found = true;\r
-    if ( probeInfo.isInput ) {\r
-      device.id[1] = lpguid;\r
-      device.validId[1] = true;\r
-    }\r
-    else {\r
-      device.id[0] = lpguid;\r
-      device.validId[0] = true;\r
-    }\r
-    dsDevices.push_back( device );\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-static const char* getErrorString( int code )\r
-{\r
-  switch ( code ) {\r
-\r
-  case DSERR_ALLOCATED:\r
-    return "Already allocated";\r
-\r
-  case DSERR_CONTROLUNAVAIL:\r
-    return "Control unavailable";\r
-\r
-  case DSERR_INVALIDPARAM:\r
-    return "Invalid parameter";\r
-\r
-  case DSERR_INVALIDCALL:\r
-    return "Invalid call";\r
-\r
-  case DSERR_GENERIC:\r
-    return "Generic error";\r
-\r
-  case DSERR_PRIOLEVELNEEDED:\r
-    return "Priority level needed";\r
-\r
-  case DSERR_OUTOFMEMORY:\r
-    return "Out of memory";\r
-\r
-  case DSERR_BADFORMAT:\r
-    return "The sample rate or the channel format is not supported";\r
-\r
-  case DSERR_UNSUPPORTED:\r
-    return "Not supported";\r
-\r
-  case DSERR_NODRIVER:\r
-    return "No driver";\r
-\r
-  case DSERR_ALREADYINITIALIZED:\r
-    return "Already initialized";\r
-\r
-  case DSERR_NOAGGREGATION:\r
-    return "No aggregation";\r
-\r
-  case DSERR_BUFFERLOST:\r
-    return "Buffer lost";\r
-\r
-  case DSERR_OTHERAPPHASPRIO:\r
-    return "Another application already has priority";\r
-\r
-  case DSERR_UNINITIALIZED:\r
-    return "Uninitialized";\r
-\r
-  default:\r
-    return "DirectSound unknown error";\r
-  }\r
-}\r
-//******************** End of __WINDOWS_DS__ *********************//\r
-#endif\r
-\r
-\r
-#if defined(__LINUX_ALSA__)\r
-\r
-#include <alsa/asoundlib.h>\r
-#include <unistd.h>\r
-\r
-  // A structure to hold various information related to the ALSA API\r
-  // implementation.\r
-struct AlsaHandle {\r
-  snd_pcm_t *handles[2];\r
-  bool synchronized;\r
-  bool xrun[2];\r
-  pthread_cond_t runnable_cv;\r
-  bool runnable;\r
-\r
-  AlsaHandle()\r
-    :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }\r
-};\r
-\r
-static void *alsaCallbackHandler( void * ptr );\r
-\r
-RtApiAlsa :: RtApiAlsa()\r
-{\r
-  // Nothing to do here.\r
-}\r
-\r
-RtApiAlsa :: ~RtApiAlsa()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-}\r
-\r
-unsigned int RtApiAlsa :: getDeviceCount( void )\r
-{\r
-  unsigned nDevices = 0;\r
-  int result, subdevice, card;\r
-  char name[64];\r
-  snd_ctl_t *handle;\r
-\r
-  // Count cards and devices\r
-  card = -1;\r
-  snd_card_next( &card );\r
-  while ( card >= 0 ) {\r
-    sprintf( name, "hw:%d", card );\r
-    result = snd_ctl_open( &handle, name, 0 );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::WARNING );\r
-      goto nextcard;\r
-    }\r
-    subdevice = -1;\r
-    while( 1 ) {\r
-      result = snd_ctl_pcm_next_device( handle, &subdevice );\r
-      if ( result < 0 ) {\r
-        errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::WARNING );\r
-        break;\r
-      }\r
-      if ( subdevice < 0 )\r
-        break;\r
-      nDevices++;\r
-    }\r
-  nextcard:\r
-    snd_ctl_close( handle );\r
-    snd_card_next( &card );\r
-  }\r
-\r
-  result = snd_ctl_open( &handle, "default", 0 );\r
-  if (result == 0) {\r
-    nDevices++;\r
-    snd_ctl_close( handle );\r
-  }\r
-\r
-  return nDevices;\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  unsigned nDevices = 0;\r
-  int result, subdevice, card;\r
-  char name[64];\r
-  snd_ctl_t *chandle;\r
-\r
-  // Count cards and devices\r
-  card = -1;\r
-  snd_card_next( &card );\r
-  while ( card >= 0 ) {\r
-    sprintf( name, "hw:%d", card );\r
-    result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::WARNING );\r
-      goto nextcard;\r
-    }\r
-    subdevice = -1;\r
-    while( 1 ) {\r
-      result = snd_ctl_pcm_next_device( chandle, &subdevice );\r
-      if ( result < 0 ) {\r
-        errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-        error( RtAudioError::WARNING );\r
-        break;\r
-      }\r
-      if ( subdevice < 0 ) break;\r
-      if ( nDevices == device ) {\r
-        sprintf( name, "hw:%d,%d", card, subdevice );\r
-        goto foundDevice;\r
-      }\r
-      nDevices++;\r
-    }\r
-  nextcard:\r
-    snd_ctl_close( chandle );\r
-    snd_card_next( &card );\r
-  }\r
-\r
-  result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
-  if ( result == 0 ) {\r
-    if ( nDevices == device ) {\r
-      strcpy( name, "default" );\r
-      goto foundDevice;\r
-    }\r
-    nDevices++;\r
-  }\r
-\r
-  if ( nDevices == 0 ) {\r
-    errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
- foundDevice:\r
-\r
-  // If a stream is already open, we cannot probe the stream devices.\r
-  // Thus, use the saved results.\r
-  if ( stream_.state != STREAM_CLOSED &&\r
-       ( stream_.device[0] == device || stream_.device[1] == device ) ) {\r
-    snd_ctl_close( chandle );\r
-    if ( device >= devices_.size() ) {\r
-      errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";\r
-      error( RtAudioError::WARNING );\r
-      return info;\r
-    }\r
-    return devices_[ device ];\r
-  }\r
-\r
-  int openMode = SND_PCM_ASYNC;\r
-  snd_pcm_stream_t stream;\r
-  snd_pcm_info_t *pcminfo;\r
-  snd_pcm_info_alloca( &pcminfo );\r
-  snd_pcm_t *phandle;\r
-  snd_pcm_hw_params_t *params;\r
-  snd_pcm_hw_params_alloca( &params );\r
-\r
-  // First try for playback unless default device (which has subdev -1)\r
-  stream = SND_PCM_STREAM_PLAYBACK;\r
-  snd_pcm_info_set_stream( pcminfo, stream );\r
-  if ( subdevice != -1 ) {\r
-    snd_pcm_info_set_device( pcminfo, subdevice );\r
-    snd_pcm_info_set_subdevice( pcminfo, 0 );\r
-\r
-    result = snd_ctl_pcm_info( chandle, pcminfo );\r
-    if ( result < 0 ) {\r
-      // Device probably doesn't support playback.\r
-      goto captureProbe;\r
-    }\r
-  }\r
-\r
-  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );\r
-  if ( result < 0 ) {\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    goto captureProbe;\r
-  }\r
-\r
-  // The device is open ... fill the parameter structure.\r
-  result = snd_pcm_hw_params_any( phandle, params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    goto captureProbe;\r
-  }\r
-\r
-  // Get output channel information.\r
-  unsigned int value;\r
-  result = snd_pcm_hw_params_get_channels_max( params, &value );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    goto captureProbe;\r
-  }\r
-  info.outputChannels = value;\r
-  snd_pcm_close( phandle );\r
-\r
- captureProbe:\r
-  stream = SND_PCM_STREAM_CAPTURE;\r
-  snd_pcm_info_set_stream( pcminfo, stream );\r
-\r
-  // Now try for capture unless default device (with subdev = -1)\r
-  if ( subdevice != -1 ) {\r
-    result = snd_ctl_pcm_info( chandle, pcminfo );\r
-    snd_ctl_close( chandle );\r
-    if ( result < 0 ) {\r
-      // Device probably doesn't support capture.\r
-      if ( info.outputChannels == 0 ) return info;\r
-      goto probeParameters;\r
-    }\r
-  }\r
-  else\r
-    snd_ctl_close( chandle );\r
-\r
-  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
-  if ( result < 0 ) {\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    if ( info.outputChannels == 0 ) return info;\r
-    goto probeParameters;\r
-  }\r
-\r
-  // The device is open ... fill the parameter structure.\r
-  result = snd_pcm_hw_params_any( phandle, params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    if ( info.outputChannels == 0 ) return info;\r
-    goto probeParameters;\r
-  }\r
-\r
-  result = snd_pcm_hw_params_get_channels_max( params, &value );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    if ( info.outputChannels == 0 ) return info;\r
-    goto probeParameters;\r
-  }\r
-  info.inputChannels = value;\r
-  snd_pcm_close( phandle );\r
-\r
-  // If device opens for both playback and capture, we determine the channels.\r
-  if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
-    info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-\r
-  // ALSA doesn't provide default devices so we'll use the first available one.\r
-  if ( device == 0 && info.outputChannels > 0 )\r
-    info.isDefaultOutput = true;\r
-  if ( device == 0 && info.inputChannels > 0 )\r
-    info.isDefaultInput = true;\r
-\r
- probeParameters:\r
-  // At this point, we just need to figure out the supported data\r
-  // formats and sample rates.  We'll proceed by opening the device in\r
-  // the direction with the maximum number of channels, or playback if\r
-  // they are equal.  This might limit our sample rate options, but so\r
-  // be it.\r
-\r
-  if ( info.outputChannels >= info.inputChannels )\r
-    stream = SND_PCM_STREAM_PLAYBACK;\r
-  else\r
-    stream = SND_PCM_STREAM_CAPTURE;\r
-  snd_pcm_info_set_stream( pcminfo, stream );\r
-\r
-  result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
-  if ( result < 0 ) {\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // The device is open ... fill the parameter structure.\r
-  result = snd_pcm_hw_params_any( phandle, params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Test our discrete set of sample rate values.\r
-  info.sampleRates.clear();\r
-  for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
-    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 )\r
-      info.sampleRates.push_back( SAMPLE_RATES[i] );\r
-  }\r
-  if ( info.sampleRates.size() == 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Probe the supported data formats ... we don't care about endian-ness just yet\r
-  snd_pcm_format_t format;\r
-  info.nativeFormats = 0;\r
-  format = SND_PCM_FORMAT_S8;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_SINT8;\r
-  format = SND_PCM_FORMAT_S16;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_SINT16;\r
-  format = SND_PCM_FORMAT_S24;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_SINT24;\r
-  format = SND_PCM_FORMAT_S32;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_SINT32;\r
-  format = SND_PCM_FORMAT_FLOAT;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_FLOAT32;\r
-  format = SND_PCM_FORMAT_FLOAT64;\r
-  if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )\r
-    info.nativeFormats |= RTAUDIO_FLOAT64;\r
-\r
-  // Check that we have at least one supported format\r
-  if ( info.nativeFormats == 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Get the device name\r
-  char *cardname;\r
-  result = snd_card_get_name( card, &cardname );\r
-  if ( result >= 0 ) {\r
-    sprintf( name, "hw:%s,%d", cardname, subdevice );\r
-    free( cardname );\r
-  }\r
-  info.name = name;\r
-\r
-  // That's all ... close the device and return\r
-  snd_pcm_close( phandle );\r
-  info.probed = true;\r
-  return info;\r
-}\r
-\r
-void RtApiAlsa :: saveDeviceInfo( void )\r
-{\r
-  devices_.clear();\r
-\r
-  unsigned int nDevices = getDeviceCount();\r
-  devices_.resize( nDevices );\r
-  for ( unsigned int i=0; i<nDevices; i++ )\r
-    devices_[i] = getDeviceInfo( i );\r
-}\r
-\r
-bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                   unsigned int firstChannel, unsigned int sampleRate,\r
-                                   RtAudioFormat format, unsigned int *bufferSize,\r
-                                   RtAudio::StreamOptions *options )\r
-\r
-{\r
-#if defined(__RTAUDIO_DEBUG__)\r
-  snd_output_t *out;\r
-  snd_output_stdio_attach(&out, stderr, 0);\r
-#endif\r
-\r
-  // I'm not using the "plug" interface ... too much inconsistent behavior.\r
-\r
-  unsigned nDevices = 0;\r
-  int result, subdevice, card;\r
-  char name[64];\r
-  snd_ctl_t *chandle;\r
-\r
-  if ( options && options->flags & RTAUDIO_ALSA_USE_DEFAULT )\r
-    snprintf(name, sizeof(name), "%s", "default");\r
-  else {\r
-    // Count cards and devices\r
-    card = -1;\r
-    snd_card_next( &card );\r
-    while ( card >= 0 ) {\r
-      sprintf( name, "hw:%d", card );\r
-      result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );\r
-      if ( result < 0 ) {\r
-        errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-        return FAILURE;\r
-      }\r
-      subdevice = -1;\r
-      while( 1 ) {\r
-        result = snd_ctl_pcm_next_device( chandle, &subdevice );\r
-        if ( result < 0 ) break;\r
-        if ( subdevice < 0 ) break;\r
-        if ( nDevices == device ) {\r
-          sprintf( name, "hw:%d,%d", card, subdevice );\r
-          snd_ctl_close( chandle );\r
-          goto foundDevice;\r
-        }\r
-        nDevices++;\r
-      }\r
-      snd_ctl_close( chandle );\r
-      snd_card_next( &card );\r
-    }\r
-\r
-    result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
-    if ( result == 0 ) {\r
-      if ( nDevices == device ) {\r
-        strcpy( name, "default" );\r
-        goto foundDevice;\r
-      }\r
-      nDevices++;\r
-    }\r
-\r
-    if ( nDevices == 0 ) {\r
-      // This should not happen because a check is made before this function is called.\r
-      errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";\r
-      return FAILURE;\r
-    }\r
-\r
-    if ( device >= nDevices ) {\r
-      // This should not happen because a check is made before this function is called.\r
-      errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!";\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
- foundDevice:\r
-\r
-  // The getDeviceInfo() function will not work for a device that is\r
-  // already open.  Thus, we'll probe the system before opening a\r
-  // stream and save the results for use by getDeviceInfo().\r
-  if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once\r
-    this->saveDeviceInfo();\r
-\r
-  snd_pcm_stream_t stream;\r
-  if ( mode == OUTPUT )\r
-    stream = SND_PCM_STREAM_PLAYBACK;\r
-  else\r
-    stream = SND_PCM_STREAM_CAPTURE;\r
-\r
-  snd_pcm_t *phandle;\r
-  int openMode = SND_PCM_ASYNC;\r
-  result = snd_pcm_open( &phandle, name, stream, openMode );\r
-  if ( result < 0 ) {\r
-    if ( mode == OUTPUT )\r
-      errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";\r
-    else\r
-      errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Fill the parameter structure.\r
-  snd_pcm_hw_params_t *hw_params;\r
-  snd_pcm_hw_params_alloca( &hw_params );\r
-  result = snd_pcm_hw_params_any( phandle, hw_params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-#if defined(__RTAUDIO_DEBUG__)\r
-  fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" );\r
-  snd_pcm_hw_params_dump( hw_params, out );\r
-#endif\r
-\r
-  // Set access ... check user preference.\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) {\r
-    stream_.userInterleaved = false;\r
-    result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );\r
-    if ( result < 0 ) {\r
-      result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );\r
-      stream_.deviceInterleaved[mode] =  true;\r
-    }\r
-    else\r
-      stream_.deviceInterleaved[mode] = false;\r
-  }\r
-  else {\r
-    stream_.userInterleaved = true;\r
-    result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );\r
-    if ( result < 0 ) {\r
-      result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );\r
-      stream_.deviceInterleaved[mode] =  false;\r
-    }\r
-    else\r
-      stream_.deviceInterleaved[mode] =  true;\r
-  }\r
-\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Determine how to set the device format.\r
-  stream_.userFormat = format;\r
-  snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN;\r
-\r
-  if ( format == RTAUDIO_SINT8 )\r
-    deviceFormat = SND_PCM_FORMAT_S8;\r
-  else if ( format == RTAUDIO_SINT16 )\r
-    deviceFormat = SND_PCM_FORMAT_S16;\r
-  else if ( format == RTAUDIO_SINT24 )\r
-    deviceFormat = SND_PCM_FORMAT_S24;\r
-  else if ( format == RTAUDIO_SINT32 )\r
-    deviceFormat = SND_PCM_FORMAT_S32;\r
-  else if ( format == RTAUDIO_FLOAT32 )\r
-    deviceFormat = SND_PCM_FORMAT_FLOAT;\r
-  else if ( format == RTAUDIO_FLOAT64 )\r
-    deviceFormat = SND_PCM_FORMAT_FLOAT64;\r
-\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) {\r
-    stream_.deviceFormat[mode] = format;\r
-    goto setFormat;\r
-  }\r
-\r
-  // The user requested format is not natively supported by the device.\r
-  deviceFormat = SND_PCM_FORMAT_FLOAT64;\r
-  if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;\r
-    goto setFormat;\r
-  }\r
-\r
-  deviceFormat = SND_PCM_FORMAT_FLOAT;\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
-    goto setFormat;\r
-  }\r
-\r
-  deviceFormat = SND_PCM_FORMAT_S32;\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-    goto setFormat;\r
-  }\r
-\r
-  deviceFormat = SND_PCM_FORMAT_S24;\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-    goto setFormat;\r
-  }\r
-\r
-  deviceFormat = SND_PCM_FORMAT_S16;\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-    goto setFormat;\r
-  }\r
-\r
-  deviceFormat = SND_PCM_FORMAT_S8;\r
-  if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {\r
-    stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-    goto setFormat;\r
-  }\r
-\r
-  // If we get here, no supported format was found.\r
-  snd_pcm_close( phandle );\r
-  errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio.";\r
-  errorText_ = errorStream_.str();\r
-  return FAILURE;\r
-\r
- setFormat:\r
-  result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Determine whether byte-swaping is necessary.\r
-  stream_.doByteSwap[mode] = false;\r
-  if ( deviceFormat != SND_PCM_FORMAT_S8 ) {\r
-    result = snd_pcm_format_cpu_endian( deviceFormat );\r
-    if ( result == 0 )\r
-      stream_.doByteSwap[mode] = true;\r
-    else if (result < 0) {\r
-      snd_pcm_close( phandle );\r
-      errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      return FAILURE;\r
-    }\r
-  }\r
-\r
-  // Set the sample rate.\r
-  result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Determine the number of channels for this device.  We support a possible\r
-  // minimum device channel number > than the value requested by the user.\r
-  stream_.nUserChannels[mode] = channels;\r
-  unsigned int value;\r
-  result = snd_pcm_hw_params_get_channels_max( hw_params, &value );\r
-  unsigned int deviceChannels = value;\r
-  if ( result < 0 || deviceChannels < channels + firstChannel ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  result = snd_pcm_hw_params_get_channels_min( hw_params, &value );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  deviceChannels = value;\r
-  if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel;\r
-  stream_.nDeviceChannels[mode] = deviceChannels;\r
-\r
-  // Set the device channels.\r
-  result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the buffer (or period) size.\r
-  int dir = 0;\r
-  snd_pcm_uframes_t periodSize = *bufferSize;\r
-  result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  *bufferSize = periodSize;\r
-\r
-  // Set the buffer number, which in ALSA is referred to as the "period".\r
-  unsigned int periods = 0;\r
-  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;\r
-  if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers;\r
-  if ( periods < 2 ) periods = 4; // a fairly safe default value\r
-  result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // If attempting to setup a duplex stream, the bufferSize parameter\r
-  // MUST be the same in both directions!\r
-  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  stream_.bufferSize = *bufferSize;\r
-\r
-  // Install the hardware configuration\r
-  result = snd_pcm_hw_params( phandle, hw_params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-#if defined(__RTAUDIO_DEBUG__)\r
-  fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");\r
-  snd_pcm_hw_params_dump( hw_params, out );\r
-#endif\r
-\r
-  // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.\r
-  snd_pcm_sw_params_t *sw_params = NULL;\r
-  snd_pcm_sw_params_alloca( &sw_params );\r
-  snd_pcm_sw_params_current( phandle, sw_params );\r
-  snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );\r
-  snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );\r
-  snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );\r
-\r
-  // The following two settings were suggested by Theo Veenker\r
-  //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );\r
-  //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );\r
-\r
-  // here are two options for a fix\r
-  //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );\r
-  snd_pcm_uframes_t val;\r
-  snd_pcm_sw_params_get_boundary( sw_params, &val );\r
-  snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );\r
-\r
-  result = snd_pcm_sw_params( phandle, sw_params );\r
-  if ( result < 0 ) {\r
-    snd_pcm_close( phandle );\r
-    errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << ".";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-#if defined(__RTAUDIO_DEBUG__)\r
-  fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");\r
-  snd_pcm_sw_params_dump( sw_params, out );\r
-#endif\r
-\r
-  // Set flags for buffer conversion\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-       stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate the ApiHandle if necessary and then save.\r
-  AlsaHandle *apiInfo = 0;\r
-  if ( stream_.apiHandle == 0 ) {\r
-    try {\r
-      apiInfo = (AlsaHandle *) new AlsaHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";\r
-      goto error;\r
-    }\r
-\r
-    if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {\r
-      errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";\r
-      goto error;\r
-    }\r
-\r
-    stream_.apiHandle = (void *) apiInfo;\r
-    apiInfo->handles[0] = 0;\r
-    apiInfo->handles[1] = 0;\r
-  }\r
-  else {\r
-    apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  }\r
-  apiInfo->handles[mode] = phandle;\r
-  phandle = 0;\r
-\r
-  // Allocate necessary internal buffers.\r
-  unsigned long bufferBytes;\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.sampleRate = sampleRate;\r
-  stream_.nBuffers = periods;\r
-  stream_.device[mode] = device;\r
-  stream_.state = STREAM_STOPPED;\r
-\r
-  // Setup the buffer conversion information structure.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
-\r
-  // Setup thread if necessary.\r
-  if ( stream_.mode == OUTPUT && mode == INPUT ) {\r
-    // We had already set up an output stream.\r
-    stream_.mode = DUPLEX;\r
-    // Link the streams if possible.\r
-    apiInfo->synchronized = false;\r
-    if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 )\r
-      apiInfo->synchronized = true;\r
-    else {\r
-      errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";\r
-      error( RtAudioError::WARNING );\r
-    }\r
-  }\r
-  else {\r
-    stream_.mode = mode;\r
-\r
-    // Setup callback thread.\r
-    stream_.callbackInfo.object = (void *) this;\r
-\r
-    // Set the thread attributes for joinable and realtime scheduling\r
-    // priority (optional).  The higher priority will only take affect\r
-    // if the program is run as root or suid. Note, under Linux\r
-    // processes with CAP_SYS_NICE privilege, a user can change\r
-    // scheduling policy and priority (thus need not be root). See\r
-    // POSIX "capabilities".\r
-    pthread_attr_t attr;\r
-    pthread_attr_init( &attr );\r
-    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );\r
-\r
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
-    if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {\r
-      // We previously attempted to increase the audio callback priority\r
-      // to SCHED_RR here via the attributes.  However, while no errors\r
-      // were reported in doing so, it did not work.  So, now this is\r
-      // done in the alsaCallbackHandler function.\r
-      stream_.callbackInfo.doRealtime = true;\r
-      int priority = options->priority;\r
-      int min = sched_get_priority_min( SCHED_RR );\r
-      int max = sched_get_priority_max( SCHED_RR );\r
-      if ( priority < min ) priority = min;\r
-      else if ( priority > max ) priority = max;\r
-      stream_.callbackInfo.priority = priority;\r
-    }\r
-#endif\r
-\r
-    stream_.callbackInfo.isRunning = true;\r
-    result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );\r
-    pthread_attr_destroy( &attr );\r
-    if ( result ) {\r
-      stream_.callbackInfo.isRunning = false;\r
-      errorText_ = "RtApiAlsa::error creating callback thread!";\r
-      goto error;\r
-    }\r
-  }\r
-\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( apiInfo ) {\r
-    pthread_cond_destroy( &apiInfo->runnable_cv );\r
-    if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
-    if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
-    delete apiInfo;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  if ( phandle) snd_pcm_close( phandle );\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.state = STREAM_CLOSED;\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiAlsa :: closeStream()\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  stream_.callbackInfo.isRunning = false;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    apiInfo->runnable = true;\r
-    pthread_cond_signal( &apiInfo->runnable_cv );\r
-  }\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-  pthread_join( stream_.callbackInfo.thread, NULL );\r
-\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    stream_.state = STREAM_STOPPED;\r
-    if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
-      snd_pcm_drop( apiInfo->handles[0] );\r
-    if ( stream_.mode == INPUT || stream_.mode == DUPLEX )\r
-      snd_pcm_drop( apiInfo->handles[1] );\r
-  }\r
-\r
-  if ( apiInfo ) {\r
-    pthread_cond_destroy( &apiInfo->runnable_cv );\r
-    if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
-    if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
-    delete apiInfo;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-void RtApiAlsa :: startStream()\r
-{\r
-  // This method calls snd_pcm_prepare if the device isn't already in that state.\r
-\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiAlsa::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  int result = 0;\r
-  snd_pcm_state_t state;\r
-  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    state = snd_pcm_state( handle[0] );\r
-    if ( state != SND_PCM_STATE_PREPARED ) {\r
-      result = snd_pcm_prepare( handle[0] );\r
-      if ( result < 0 ) {\r
-        errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-        goto unlock;\r
-      }\r
-    }\r
-  }\r
-\r
-  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
-    result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open\r
-    state = snd_pcm_state( handle[1] );\r
-    if ( state != SND_PCM_STATE_PREPARED ) {\r
-      result = snd_pcm_prepare( handle[1] );\r
-      if ( result < 0 ) {\r
-        errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-        goto unlock;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_RUNNING;\r
-\r
- unlock:\r
-  apiInfo->runnable = true;\r
-  pthread_cond_signal( &apiInfo->runnable_cv );\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( result >= 0 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiAlsa :: stopStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  int result = 0;\r
-  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    if ( apiInfo->synchronized ) \r
-      result = snd_pcm_drop( handle[0] );\r
-    else\r
-      result = snd_pcm_drain( handle[0] );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
-    result = snd_pcm_drop( handle[1] );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
- unlock:\r
-  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( result >= 0 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiAlsa :: abortStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  int result = 0;\r
-  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    result = snd_pcm_drop( handle[0] );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
-  if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
-    result = snd_pcm_drop( handle[1] );\r
-    if ( result < 0 ) {\r
-      errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
- unlock:\r
-  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( result >= 0 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiAlsa :: callbackEvent()\r
-{\r
-  AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_LOCK( &stream_.mutex );\r
-    while ( !apiInfo->runnable )\r
-      pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );\r
-\r
-    if ( stream_.state != STREAM_RUNNING ) {\r
-      MUTEX_UNLOCK( &stream_.mutex );\r
-      return;\r
-    }\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-  }\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  int doStopStream = 0;\r
-  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
-  double streamTime = getStreamTime();\r
-  RtAudioStreamStatus status = 0;\r
-  if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) {\r
-    status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-    apiInfo->xrun[0] = false;\r
-  }\r
-  if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) {\r
-    status |= RTAUDIO_INPUT_OVERFLOW;\r
-    apiInfo->xrun[1] = false;\r
-  }\r
-  doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                           stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );\r
-\r
-  if ( doStopStream == 2 ) {\r
-    abortStream();\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  // The state might change while waiting on a mutex.\r
-  if ( stream_.state == STREAM_STOPPED ) goto unlock;\r
-\r
-  int result;\r
-  char *buffer;\r
-  int channels;\r
-  snd_pcm_t **handle;\r
-  snd_pcm_sframes_t frames;\r
-  RtAudioFormat format;\r
-  handle = (snd_pcm_t **) apiInfo->handles;\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Setup parameters.\r
-    if ( stream_.doConvertBuffer[1] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      channels = stream_.nDeviceChannels[1];\r
-      format = stream_.deviceFormat[1];\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[1];\r
-      channels = stream_.nUserChannels[1];\r
-      format = stream_.userFormat;\r
-    }\r
-\r
-    // Read samples from device in interleaved/non-interleaved format.\r
-    if ( stream_.deviceInterleaved[1] )\r
-      result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize );\r
-    else {\r
-      void *bufs[channels];\r
-      size_t offset = stream_.bufferSize * formatBytes( format );\r
-      for ( int i=0; i<channels; i++ )\r
-        bufs[i] = (void *) (buffer + (i * offset));\r
-      result = snd_pcm_readn( handle[1], bufs, stream_.bufferSize );\r
-    }\r
-\r
-    if ( result < (int) stream_.bufferSize ) {\r
-      // Either an error or overrun occured.\r
-      if ( result == -EPIPE ) {\r
-        snd_pcm_state_t state = snd_pcm_state( handle[1] );\r
-        if ( state == SND_PCM_STATE_XRUN ) {\r
-          apiInfo->xrun[1] = true;\r
-          result = snd_pcm_prepare( handle[1] );\r
-          if ( result < 0 ) {\r
-            errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << ".";\r
-            errorText_ = errorStream_.str();\r
-          }\r
-        }\r
-        else {\r
-          errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";\r
-          errorText_ = errorStream_.str();\r
-        }\r
-      }\r
-      else {\r
-        errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-      }\r
-      error( RtAudioError::WARNING );\r
-      goto tryOutput;\r
-    }\r
-\r
-    // Do byte swapping if necessary.\r
-    if ( stream_.doByteSwap[1] )\r
-      byteSwapBuffer( buffer, stream_.bufferSize * channels, format );\r
-\r
-    // Do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[1] )\r
-      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
-\r
-    // Check stream latency\r
-    result = snd_pcm_delay( handle[1], &frames );\r
-    if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;\r
-  }\r
-\r
- tryOutput:\r
-\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Setup parameters and do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[0] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-      channels = stream_.nDeviceChannels[0];\r
-      format = stream_.deviceFormat[0];\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[0];\r
-      channels = stream_.nUserChannels[0];\r
-      format = stream_.userFormat;\r
-    }\r
-\r
-    // Do byte swapping if necessary.\r
-    if ( stream_.doByteSwap[0] )\r
-      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);\r
-\r
-    // Write samples to device in interleaved/non-interleaved format.\r
-    if ( stream_.deviceInterleaved[0] )\r
-      result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize );\r
-    else {\r
-      void *bufs[channels];\r
-      size_t offset = stream_.bufferSize * formatBytes( format );\r
-      for ( int i=0; i<channels; i++ )\r
-        bufs[i] = (void *) (buffer + (i * offset));\r
-      result = snd_pcm_writen( handle[0], bufs, stream_.bufferSize );\r
-    }\r
-\r
-    if ( result < (int) stream_.bufferSize ) {\r
-      // Either an error or underrun occured.\r
-      if ( result == -EPIPE ) {\r
-        snd_pcm_state_t state = snd_pcm_state( handle[0] );\r
-        if ( state == SND_PCM_STATE_XRUN ) {\r
-          apiInfo->xrun[0] = true;\r
-          result = snd_pcm_prepare( handle[0] );\r
-          if ( result < 0 ) {\r
-            errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";\r
-            errorText_ = errorStream_.str();\r
-          }\r
-        }\r
-        else {\r
-          errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";\r
-          errorText_ = errorStream_.str();\r
-        }\r
-      }\r
-      else {\r
-        errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";\r
-        errorText_ = errorStream_.str();\r
-      }\r
-      error( RtAudioError::WARNING );\r
-      goto unlock;\r
-    }\r
-\r
-    // Check stream latency\r
-    result = snd_pcm_delay( handle[0], &frames );\r
-    if ( result == 0 && frames > 0 ) stream_.latency[0] = frames;\r
-  }\r
-\r
- unlock:\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  RtApi::tickStreamTime();\r
-  if ( doStopStream == 1 ) this->stopStream();\r
-}\r
-\r
-static void *alsaCallbackHandler( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiAlsa *object = (RtApiAlsa *) info->object;\r
-  bool *isRunning = &info->isRunning;\r
-\r
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
-  if ( &info->doRealtime ) {\r
-    pthread_t tID = pthread_self();     // ID of this thread\r
-    sched_param prio = { info->priority }; // scheduling priority of thread\r
-    pthread_setschedparam( tID, SCHED_RR, &prio );\r
-  }\r
-#endif\r
-\r
-  while ( *isRunning == true ) {\r
-    pthread_testcancel();\r
-    object->callbackEvent();\r
-  }\r
-\r
-  pthread_exit( NULL );\r
-}\r
-\r
-//******************** End of __LINUX_ALSA__ *********************//\r
-#endif\r
-\r
-#if defined(__LINUX_PULSE__)\r
-\r
-// Code written by Peter Meerwald, pmeerw@pmeerw.net\r
-// and Tristan Matthews.\r
-\r
-#include <pulse/error.h>\r
-#include <pulse/simple.h>\r
-#include <cstdio>\r
-\r
-static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
-                                                      44100, 48000, 96000, 0};\r
-\r
-struct rtaudio_pa_format_mapping_t {\r
-  RtAudioFormat rtaudio_format;\r
-  pa_sample_format_t pa_format;\r
-};\r
-\r
-static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {\r
-  {RTAUDIO_SINT16, PA_SAMPLE_S16LE},\r
-  {RTAUDIO_SINT32, PA_SAMPLE_S32LE},\r
-  {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},\r
-  {0, PA_SAMPLE_INVALID}};\r
-\r
-struct PulseAudioHandle {\r
-  pa_simple *s_play;\r
-  pa_simple *s_rec;\r
-  pthread_t thread;\r
-  pthread_cond_t runnable_cv;\r
-  bool runnable;\r
-  PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { }\r
-};\r
-\r
-RtApiPulse::~RtApiPulse()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED )\r
-    closeStream();\r
-}\r
-\r
-unsigned int RtApiPulse::getDeviceCount( void )\r
-{\r
-  return 1;\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = true;\r
-  info.name = "PulseAudio";\r
-  info.outputChannels = 2;\r
-  info.inputChannels = 2;\r
-  info.duplexChannels = 2;\r
-  info.isDefaultOutput = true;\r
-  info.isDefaultInput = true;\r
-\r
-  for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )\r
-    info.sampleRates.push_back( *sr );\r
-\r
-  info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;\r
-\r
-  return info;\r
-}\r
-\r
-static void *pulseaudio_callback( void * user )\r
-{\r
-  CallbackInfo *cbi = static_cast<CallbackInfo *>( user );\r
-  RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );\r
-  volatile bool *isRunning = &cbi->isRunning;\r
-\r
-  while ( *isRunning ) {\r
-    pthread_testcancel();\r
-    context->callbackEvent();\r
-  }\r
-\r
-  pthread_exit( NULL );\r
-}\r
-\r
-void RtApiPulse::closeStream( void )\r
-{\r
-  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
-\r
-  stream_.callbackInfo.isRunning = false;\r
-  if ( pah ) {\r
-    MUTEX_LOCK( &stream_.mutex );\r
-    if ( stream_.state == STREAM_STOPPED ) {\r
-      pah->runnable = true;\r
-      pthread_cond_signal( &pah->runnable_cv );\r
-    }\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-    pthread_join( pah->thread, 0 );\r
-    if ( pah->s_play ) {\r
-      pa_simple_flush( pah->s_play, NULL );\r
-      pa_simple_free( pah->s_play );\r
-    }\r
-    if ( pah->s_rec )\r
-      pa_simple_free( pah->s_rec );\r
-\r
-    pthread_cond_destroy( &pah->runnable_cv );\r
-    delete pah;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  if ( stream_.userBuffer[0] ) {\r
-    free( stream_.userBuffer[0] );\r
-    stream_.userBuffer[0] = 0;\r
-  }\r
-  if ( stream_.userBuffer[1] ) {\r
-    free( stream_.userBuffer[1] );\r
-    stream_.userBuffer[1] = 0;\r
-  }\r
-\r
-  stream_.state = STREAM_CLOSED;\r
-  stream_.mode = UNINITIALIZED;\r
-}\r
-\r
-void RtApiPulse::callbackEvent( void )\r
-{\r
-  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
-\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_LOCK( &stream_.mutex );\r
-    while ( !pah->runnable )\r
-      pthread_cond_wait( &pah->runnable_cv, &stream_.mutex );\r
-\r
-    if ( stream_.state != STREAM_RUNNING ) {\r
-      MUTEX_UNLOCK( &stream_.mutex );\r
-      return;\r
-    }\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-  }\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "\r
-      "this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
-  double streamTime = getStreamTime();\r
-  RtAudioStreamStatus status = 0;\r
-  int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],\r
-                               stream_.bufferSize, streamTime, status,\r
-                               stream_.callbackInfo.userData );\r
-\r
-  if ( doStopStream == 2 ) {\r
-    abortStream();\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-  void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];\r
-  void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];\r
-\r
-  if ( stream_.state != STREAM_RUNNING )\r
-    goto unlock;\r
-\r
-  int pa_error;\r
-  size_t bytes;\r
-  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    if ( stream_.doConvertBuffer[OUTPUT] ) {\r
-        convertBuffer( stream_.deviceBuffer,\r
-                       stream_.userBuffer[OUTPUT],\r
-                       stream_.convertInfo[OUTPUT] );\r
-        bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *\r
-                formatBytes( stream_.deviceFormat[OUTPUT] );\r
-    } else\r
-        bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *\r
-                formatBytes( stream_.userFormat );\r
-\r
-    if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {\r
-      errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::WARNING );\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {\r
-    if ( stream_.doConvertBuffer[INPUT] )\r
-      bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *\r
-        formatBytes( stream_.deviceFormat[INPUT] );\r
-    else\r
-      bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *\r
-        formatBytes( stream_.userFormat );\r
-            \r
-    if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {\r
-      errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtAudioError::WARNING );\r
-    }\r
-    if ( stream_.doConvertBuffer[INPUT] ) {\r
-      convertBuffer( stream_.userBuffer[INPUT],\r
-                     stream_.deviceBuffer,\r
-                     stream_.convertInfo[INPUT] );\r
-    }\r
-  }\r
-\r
- unlock:\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-  RtApi::tickStreamTime();\r
-\r
-  if ( doStopStream == 1 )\r
-    stopStream();\r
-}\r
-\r
-void RtApiPulse::startStream( void )\r
-{\r
-  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiPulse::startStream(): the stream is not open!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiPulse::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  stream_.state = STREAM_RUNNING;\r
-\r
-  pah->runnable = true;\r
-  pthread_cond_signal( &pah->runnable_cv );\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-}\r
-\r
-void RtApiPulse::stopStream( void )\r
-{\r
-  PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiPulse::stopStream(): the stream is not open!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  if ( pah && pah->s_play ) {\r
-    int pa_error;\r
-    if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {\r
-      errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      MUTEX_UNLOCK( &stream_.mutex );\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-}\r
-\r
-void RtApiPulse::abortStream( void )\r
-{\r
-  PulseAudioHandle *pah = static_cast<PulseAudioHandle*>( stream_.apiHandle );\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiPulse::abortStream(): the stream is not open!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return;\r
-  }\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  if ( pah && pah->s_play ) {\r
-    int pa_error;\r
-    if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {\r
-      errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      MUTEX_UNLOCK( &stream_.mutex );\r
-      error( RtAudioError::SYSTEM_ERROR );\r
-      return;\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-}\r
-\r
-bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,\r
-                                  unsigned int channels, unsigned int firstChannel,\r
-                                  unsigned int sampleRate, RtAudioFormat format,\r
-                                  unsigned int *bufferSize, RtAudio::StreamOptions *options )\r
-{\r
-  PulseAudioHandle *pah = 0;\r
-  unsigned long bufferBytes = 0;\r
-  pa_sample_spec ss;\r
-\r
-  if ( device != 0 ) return false;\r
-  if ( mode != INPUT && mode != OUTPUT ) return false;\r
-  if ( channels != 1 && channels != 2 ) {\r
-    errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";\r
-    return false;\r
-  }\r
-  ss.channels = channels;\r
-\r
-  if ( firstChannel != 0 ) return false;\r
-\r
-  bool sr_found = false;\r
-  for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) {\r
-    if ( sampleRate == *sr ) {\r
-      sr_found = true;\r
-      stream_.sampleRate = sampleRate;\r
-      ss.rate = sampleRate;\r
-      break;\r
-    }\r
-  }\r
-  if ( !sr_found ) {\r
-    errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate.";\r
-    return false;\r
-  }\r
-\r
-  bool sf_found = 0;\r
-  for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;\r
-        sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) {\r
-    if ( format == sf->rtaudio_format ) {\r
-      sf_found = true;\r
-      stream_.userFormat = sf->rtaudio_format;\r
-      stream_.deviceFormat[mode] = stream_.userFormat;\r
-      ss.format = sf->pa_format;\r
-      break;\r
-    }\r
-  }\r
-  if ( !sf_found ) { // Use internal data format conversion.\r
-    stream_.userFormat = format;\r
-    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;\r
-    ss.format = PA_SAMPLE_FLOAT32LE;\r
-  }\r
-\r
-  // Set other stream parameters.\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
-  else stream_.userInterleaved = true;\r
-  stream_.deviceInterleaved[mode] = true;\r
-  stream_.nBuffers = 1;\r
-  stream_.doByteSwap[mode] = false;\r
-  stream_.nUserChannels[mode] = channels;\r
-  stream_.nDeviceChannels[mode] = channels + firstChannel;\r
-  stream_.channelOffset[mode] = 0;\r
-  std::string streamName = "RtAudio";\r
-\r
-  // Set flags for buffer conversion.\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate necessary internal buffers.\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-  stream_.bufferSize = *bufferSize;\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.device[mode] = device;\r
-\r
-  // Setup the buffer conversion information structure.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
-\r
-  if ( !stream_.apiHandle ) {\r
-    PulseAudioHandle *pah = new PulseAudioHandle;\r
-    if ( !pah ) {\r
-      errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle.";\r
-      goto error;\r
-    }\r
-\r
-    stream_.apiHandle = pah;\r
-    if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) {\r
-      errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable.";\r
-      goto error;\r
-    }\r
-  }\r
-  pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
-\r
-  int error;\r
-  if ( !options->streamName.empty() ) streamName = options->streamName;\r
-  switch ( mode ) {\r
-  case INPUT:\r
-    pa_buffer_attr buffer_attr;\r
-    buffer_attr.fragsize = bufferBytes;\r
-    buffer_attr.maxlength = -1;\r
-\r
-    pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );\r
-    if ( !pah->s_rec ) {\r
-      errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";\r
-      goto error;\r
-    }\r
-    break;\r
-  case OUTPUT:\r
-    pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );\r
-    if ( !pah->s_play ) {\r
-      errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";\r
-      goto error;\r
-    }\r
-    break;\r
-  default:\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.mode == UNINITIALIZED )\r
-    stream_.mode = mode;\r
-  else if ( stream_.mode == mode )\r
-    goto error;\r
-  else\r
-    stream_.mode = DUPLEX;\r
-\r
-  if ( !stream_.callbackInfo.isRunning ) {\r
-    stream_.callbackInfo.object = this;\r
-    stream_.callbackInfo.isRunning = true;\r
-    if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {\r
-      errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";\r
-      goto error;\r
-    }\r
-  }\r
-\r
-  stream_.state = STREAM_STOPPED;\r
-  return true;\r
\r
- error:\r
-  if ( pah && stream_.callbackInfo.isRunning ) {\r
-    pthread_cond_destroy( &pah->runnable_cv );\r
-    delete pah;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  return FAILURE;\r
-}\r
-\r
-//******************** End of __LINUX_PULSE__ *********************//\r
-#endif\r
-\r
-#if defined(__LINUX_OSS__)\r
-\r
-#include <unistd.h>\r
-#include <sys/ioctl.h>\r
-#include <unistd.h>\r
-#include <fcntl.h>\r
-#include <sys/soundcard.h>\r
-#include <errno.h>\r
-#include <math.h>\r
-\r
-static void *ossCallbackHandler(void * ptr);\r
-\r
-// A structure to hold various information related to the OSS API\r
-// implementation.\r
-struct OssHandle {\r
-  int id[2];    // device ids\r
-  bool xrun[2];\r
-  bool triggered;\r
-  pthread_cond_t runnable;\r
-\r
-  OssHandle()\r
-    :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
-};\r
-\r
-RtApiOss :: RtApiOss()\r
-{\r
-  // Nothing to do here.\r
-}\r
-\r
-RtApiOss :: ~RtApiOss()\r
-{\r
-  if ( stream_.state != STREAM_CLOSED ) closeStream();\r
-}\r
-\r
-unsigned int RtApiOss :: getDeviceCount( void )\r
-{\r
-  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
-  if ( mixerfd == -1 ) {\r
-    errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  oss_sysinfo sysinfo;\r
-  if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";\r
-    error( RtAudioError::WARNING );\r
-    return 0;\r
-  }\r
-\r
-  close( mixerfd );\r
-  return sysinfo.numaudios;\r
-}\r
-\r
-RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )\r
-{\r
-  RtAudio::DeviceInfo info;\r
-  info.probed = false;\r
-\r
-  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
-  if ( mixerfd == -1 ) {\r
-    errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  oss_sysinfo sysinfo;\r
-  int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );\r
-  if ( result == -1 ) {\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  unsigned nDevices = sysinfo.numaudios;\r
-  if ( nDevices == 0 ) {\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::getDeviceInfo: no devices found!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";\r
-    error( RtAudioError::INVALID_USE );\r
-    return info;\r
-  }\r
-\r
-  oss_audioinfo ainfo;\r
-  ainfo.dev = device;\r
-  result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );\r
-  close( mixerfd );\r
-  if ( result == -1 ) {\r
-    errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Probe channels\r
-  if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels;\r
-  if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels;\r
-  if ( ainfo.caps & PCM_CAP_DUPLEX ) {\r
-    if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX )\r
-      info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;\r
-  }\r
-\r
-  // Probe data formats ... do for input\r
-  unsigned long mask = ainfo.iformats;\r
-  if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE )\r
-    info.nativeFormats |= RTAUDIO_SINT16;\r
-  if ( mask & AFMT_S8 )\r
-    info.nativeFormats |= RTAUDIO_SINT8;\r
-  if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )\r
-    info.nativeFormats |= RTAUDIO_SINT32;\r
-  if ( mask & AFMT_FLOAT )\r
-    info.nativeFormats |= RTAUDIO_FLOAT32;\r
-  if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )\r
-    info.nativeFormats |= RTAUDIO_SINT24;\r
-\r
-  // Check that we have at least one supported format\r
-  if ( info.nativeFormats == 0 ) {\r
-    errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-    return info;\r
-  }\r
-\r
-  // Probe the supported sample rates.\r
-  info.sampleRates.clear();\r
-  if ( ainfo.nrates ) {\r
-    for ( unsigned int i=0; i<ainfo.nrates; i++ ) {\r
-      for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-        if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {\r
-          info.sampleRates.push_back( SAMPLE_RATES[k] );\r
-          break;\r
-        }\r
-      }\r
-    }\r
-  }\r
-  else {\r
-    // Check min and max rate values;\r
-    for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] )\r
-        info.sampleRates.push_back( SAMPLE_RATES[k] );\r
-    }\r
-  }\r
-\r
-  if ( info.sampleRates.size() == 0 ) {\r
-    errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    error( RtAudioError::WARNING );\r
-  }\r
-  else {\r
-    info.probed = true;\r
-    info.name = ainfo.name;\r
-  }\r
-\r
-  return info;\r
-}\r
-\r
-\r
-bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                                  unsigned int firstChannel, unsigned int sampleRate,\r
-                                  RtAudioFormat format, unsigned int *bufferSize,\r
-                                  RtAudio::StreamOptions *options )\r
-{\r
-  int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
-  if ( mixerfd == -1 ) {\r
-    errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'.";\r
-    return FAILURE;\r
-  }\r
-\r
-  oss_sysinfo sysinfo;\r
-  int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );\r
-  if ( result == -1 ) {\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required.";\r
-    return FAILURE;\r
-  }\r
-\r
-  unsigned nDevices = sysinfo.numaudios;\r
-  if ( nDevices == 0 ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::probeDeviceOpen: no devices found!";\r
-    return FAILURE;\r
-  }\r
-\r
-  if ( device >= nDevices ) {\r
-    // This should not happen because a check is made before this function is called.\r
-    close( mixerfd );\r
-    errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!";\r
-    return FAILURE;\r
-  }\r
-\r
-  oss_audioinfo ainfo;\r
-  ainfo.dev = device;\r
-  result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );\r
-  close( mixerfd );\r
-  if ( result == -1 ) {\r
-    errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Check if device supports input or output\r
-  if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) ||\r
-       ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) {\r
-    if ( mode == OUTPUT )\r
-      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output.";\r
-    else\r
-      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  int flags = 0;\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  if ( mode == OUTPUT )\r
-    flags |= O_WRONLY;\r
-  else { // mode == INPUT\r
-    if (stream_.mode == OUTPUT && stream_.device[0] == device) {\r
-      // We just set the same device for playback ... close and reopen for duplex (OSS only).\r
-      close( handle->id[0] );\r
-      handle->id[0] = 0;\r
-      if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) {\r
-        errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode.";\r
-        errorText_ = errorStream_.str();\r
-        return FAILURE;\r
-      }\r
-      // Check that the number previously set channels is the same.\r
-      if ( stream_.nUserChannels[0] != channels ) {\r
-        errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ").";\r
-        errorText_ = errorStream_.str();\r
-        return FAILURE;\r
-      }\r
-      flags |= O_RDWR;\r
-    }\r
-    else\r
-      flags |= O_RDONLY;\r
-  }\r
-\r
-  // Set exclusive access if specified.\r
-  if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL;\r
-\r
-  // Try to open the device.\r
-  int fd;\r
-  fd = open( ainfo.devnode, flags, 0 );\r
-  if ( fd == -1 ) {\r
-    if ( errno == EBUSY )\r
-      errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy.";\r
-    else\r
-      errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // For duplex operation, specifically set this mode (this doesn't seem to work).\r
-  /*\r
-    if ( flags | O_RDWR ) {\r
-    result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );\r
-    if ( result == -1) {\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-    }\r
-    }\r
-  */\r
-\r
-  // Check the device channel support.\r
-  stream_.nUserChannels[mode] = channels;\r
-  if ( ainfo.max_channels < (int)(channels + firstChannel) ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the number of channels.\r
-  int deviceChannels = channels + firstChannel;\r
-  result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels );\r
-  if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  stream_.nDeviceChannels[mode] = deviceChannels;\r
-\r
-  // Get the data format mask\r
-  int mask;\r
-  result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask );\r
-  if ( result == -1 ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Determine how to set the device format.\r
-  stream_.userFormat = format;\r
-  int deviceFormat = -1;\r
-  stream_.doByteSwap[mode] = false;\r
-  if ( format == RTAUDIO_SINT8 ) {\r
-    if ( mask & AFMT_S8 ) {\r
-      deviceFormat = AFMT_S8;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_SINT16 ) {\r
-    if ( mask & AFMT_S16_NE ) {\r
-      deviceFormat = AFMT_S16_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-    }\r
-    else if ( mask & AFMT_S16_OE ) {\r
-      deviceFormat = AFMT_S16_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_SINT24 ) {\r
-    if ( mask & AFMT_S24_NE ) {\r
-      deviceFormat = AFMT_S24_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-    }\r
-    else if ( mask & AFMT_S24_OE ) {\r
-      deviceFormat = AFMT_S24_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_SINT32 ) {\r
-    if ( mask & AFMT_S32_NE ) {\r
-      deviceFormat = AFMT_S32_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-    }\r
-    else if ( mask & AFMT_S32_OE ) {\r
-      deviceFormat = AFMT_S32_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-  }\r
-\r
-  if ( deviceFormat == -1 ) {\r
-    // The user requested format is not natively supported by the device.\r
-    if ( mask & AFMT_S16_NE ) {\r
-      deviceFormat = AFMT_S16_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-    }\r
-    else if ( mask & AFMT_S32_NE ) {\r
-      deviceFormat = AFMT_S32_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-    }\r
-    else if ( mask & AFMT_S24_NE ) {\r
-      deviceFormat = AFMT_S24_NE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-    }\r
-    else if ( mask & AFMT_S16_OE ) {\r
-      deviceFormat = AFMT_S16_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT16;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-    else if ( mask & AFMT_S32_OE ) {\r
-      deviceFormat = AFMT_S32_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT32;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-    else if ( mask & AFMT_S24_OE ) {\r
-      deviceFormat = AFMT_S24_OE;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT24;\r
-      stream_.doByteSwap[mode] = true;\r
-    }\r
-    else if ( mask & AFMT_S8) {\r
-      deviceFormat = AFMT_S8;\r
-      stream_.deviceFormat[mode] = RTAUDIO_SINT8;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceFormat[mode] == 0 ) {\r
-    // This really shouldn't happen ...\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio.";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Set the data format.\r
-  int temp = deviceFormat;\r
-  result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat );\r
-  if ( result == -1 || deviceFormat != temp ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Attempt to set the buffer size.  According to OSS, the minimum\r
-  // number of buffers is two.  The supposed minimum buffer size is 16\r
-  // bytes, so that will be our lower bound.  The argument to this\r
-  // call is in the form 0xMMMMSSSS (hex), where the buffer size (in\r
-  // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.\r
-  // We'll check the actual value used near the end of the setup\r
-  // procedure.\r
-  int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels;\r
-  if ( ossBufferBytes < 16 ) ossBufferBytes = 16;\r
-  int buffers = 0;\r
-  if ( options ) buffers = options->numberOfBuffers;\r
-  if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2;\r
-  if ( buffers < 2 ) buffers = 3;\r
-  temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) );\r
-  result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp );\r
-  if ( result == -1 ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  stream_.nBuffers = buffers;\r
-\r
-  // Save buffer size (in sample frames).\r
-  *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels );\r
-  stream_.bufferSize = *bufferSize;\r
-\r
-  // Set the sample rate.\r
-  int srate = sampleRate;\r
-  result = ioctl( fd, SNDCTL_DSP_SPEED, &srate );\r
-  if ( result == -1 ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-\r
-  // Verify the sample rate setup worked.\r
-  if ( abs( srate - sampleRate ) > 100 ) {\r
-    close( fd );\r
-    errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";\r
-    errorText_ = errorStream_.str();\r
-    return FAILURE;\r
-  }\r
-  stream_.sampleRate = sampleRate;\r
-\r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) {\r
-    // We're doing duplex setup here.\r
-    stream_.deviceFormat[0] = stream_.deviceFormat[1];\r
-    stream_.nDeviceChannels[0] = deviceChannels;\r
-  }\r
-\r
-  // Set interleaving parameters.\r
-  stream_.userInterleaved = true;\r
-  stream_.deviceInterleaved[mode] =  true;\r
-  if ( options && options->flags & RTAUDIO_NONINTERLEAVED )\r
-    stream_.userInterleaved = false;\r
-\r
-  // Set flags for buffer conversion\r
-  stream_.doConvertBuffer[mode] = false;\r
-  if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )\r
-    stream_.doConvertBuffer[mode] = true;\r
-  if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
-       stream_.nUserChannels[mode] > 1 )\r
-    stream_.doConvertBuffer[mode] = true;\r
-\r
-  // Allocate the stream handles if necessary and then save.\r
-  if ( stream_.apiHandle == 0 ) {\r
-    try {\r
-      handle = new OssHandle;\r
-    }\r
-    catch ( std::bad_alloc& ) {\r
-      errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory.";\r
-      goto error;\r
-    }\r
-\r
-    if ( pthread_cond_init( &handle->runnable, NULL ) ) {\r
-      errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";\r
-      goto error;\r
-    }\r
-\r
-    stream_.apiHandle = (void *) handle;\r
-  }\r
-  else {\r
-    handle = (OssHandle *) stream_.apiHandle;\r
-  }\r
-  handle->id[mode] = fd;\r
-\r
-  // Allocate necessary internal buffers.\r
-  unsigned long bufferBytes;\r
-  bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
-  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
-  if ( stream_.userBuffer[mode] == NULL ) {\r
-    errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory.";\r
-    goto error;\r
-  }\r
-\r
-  if ( stream_.doConvertBuffer[mode] ) {\r
-\r
-    bool makeBuffer = true;\r
-    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( mode == INPUT ) {\r
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
-      }\r
-    }\r
-\r
-    if ( makeBuffer ) {\r
-      bufferBytes *= *bufferSize;\r
-      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
-      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
-      if ( stream_.deviceBuffer == NULL ) {\r
-        errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory.";\r
-        goto error;\r
-      }\r
-    }\r
-  }\r
-\r
-  stream_.device[mode] = device;\r
-  stream_.state = STREAM_STOPPED;\r
-\r
-  // Setup the buffer conversion information structure.\r
-  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
-\r
-  // Setup thread if necessary.\r
-  if ( stream_.mode == OUTPUT && mode == INPUT ) {\r
-    // We had already set up an output stream.\r
-    stream_.mode = DUPLEX;\r
-    if ( stream_.device[0] == device ) handle->id[0] = fd;\r
-  }\r
-  else {\r
-    stream_.mode = mode;\r
-\r
-    // Setup callback thread.\r
-    stream_.callbackInfo.object = (void *) this;\r
-\r
-    // Set the thread attributes for joinable and realtime scheduling\r
-    // priority.  The higher priority will only take affect if the\r
-    // program is run as root or suid.\r
-    pthread_attr_t attr;\r
-    pthread_attr_init( &attr );\r
-    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );\r
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
-    if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {\r
-      struct sched_param param;\r
-      int priority = options->priority;\r
-      int min = sched_get_priority_min( SCHED_RR );\r
-      int max = sched_get_priority_max( SCHED_RR );\r
-      if ( priority < min ) priority = min;\r
-      else if ( priority > max ) priority = max;\r
-      param.sched_priority = priority;\r
-      pthread_attr_setschedparam( &attr, &param );\r
-      pthread_attr_setschedpolicy( &attr, SCHED_RR );\r
-    }\r
-    else\r
-      pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
-#else\r
-    pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
-#endif\r
-\r
-    stream_.callbackInfo.isRunning = true;\r
-    result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );\r
-    pthread_attr_destroy( &attr );\r
-    if ( result ) {\r
-      stream_.callbackInfo.isRunning = false;\r
-      errorText_ = "RtApiOss::error creating callback thread!";\r
-      goto error;\r
-    }\r
-  }\r
-\r
-  return SUCCESS;\r
-\r
- error:\r
-  if ( handle ) {\r
-    pthread_cond_destroy( &handle->runnable );\r
-    if ( handle->id[0] ) close( handle->id[0] );\r
-    if ( handle->id[1] ) close( handle->id[1] );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  return FAILURE;\r
-}\r
-\r
-void RtApiOss :: closeStream()\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiOss::closeStream(): no open stream to close!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  stream_.callbackInfo.isRunning = false;\r
-  MUTEX_LOCK( &stream_.mutex );\r
-  if ( stream_.state == STREAM_STOPPED )\r
-    pthread_cond_signal( &handle->runnable );\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-  pthread_join( stream_.callbackInfo.thread, NULL );\r
-\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )\r
-      ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
-    else\r
-      ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
-    stream_.state = STREAM_STOPPED;\r
-  }\r
-\r
-  if ( handle ) {\r
-    pthread_cond_destroy( &handle->runnable );\r
-    if ( handle->id[0] ) close( handle->id[0] );\r
-    if ( handle->id[1] ) close( handle->id[1] );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
-\r
-  for ( int i=0; i<2; i++ ) {\r
-    if ( stream_.userBuffer[i] ) {\r
-      free( stream_.userBuffer[i] );\r
-      stream_.userBuffer[i] = 0;\r
-    }\r
-  }\r
-\r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
-  }\r
-\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-}\r
-\r
-void RtApiOss :: startStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_RUNNING ) {\r
-    errorText_ = "RtApiOss::startStream(): the stream is already running!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  stream_.state = STREAM_RUNNING;\r
-\r
-  // No need to do anything else here ... OSS automatically starts\r
-  // when fed samples.\r
-\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  pthread_cond_signal( &handle->runnable );\r
-}\r
-\r
-void RtApiOss :: stopStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  // The state might change while waiting on a mutex.\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-    return;\r
-  }\r
-\r
-  int result = 0;\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Flush the output with zeros a few times.\r
-    char *buffer;\r
-    int samples;\r
-    RtAudioFormat format;\r
-\r
-    if ( stream_.doConvertBuffer[0] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      samples = stream_.bufferSize * stream_.nDeviceChannels[0];\r
-      format = stream_.deviceFormat[0];\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[0];\r
-      samples = stream_.bufferSize * stream_.nUserChannels[0];\r
-      format = stream_.userFormat;\r
-    }\r
-\r
-    memset( buffer, 0, samples * formatBytes(format) );\r
-    for ( unsigned int i=0; i<stream_.nBuffers+1; i++ ) {\r
-      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
-      if ( result == -1 ) {\r
-        errorText_ = "RtApiOss::stopStream: audio write error.";\r
-        error( RtAudioError::WARNING );\r
-      }\r
-    }\r
-\r
-    result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
-    if ( result == -1 ) {\r
-      errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-    handle->triggered = false;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {\r
-    result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
-    if ( result == -1 ) {\r
-      errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
- unlock:\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( result != -1 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiOss :: abortStream()\r
-{\r
-  verifyStream();\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  // The state might change while waiting on a mutex.\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-    return;\r
-  }\r
-\r
-  int result = 0;\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-    result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );\r
-    if ( result == -1 ) {\r
-      errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-    handle->triggered = false;\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {\r
-    result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );\r
-    if ( result == -1 ) {\r
-      errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";\r
-      errorText_ = errorStream_.str();\r
-      goto unlock;\r
-    }\r
-  }\r
-\r
- unlock:\r
-  stream_.state = STREAM_STOPPED;\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  if ( result != -1 ) return;\r
-  error( RtAudioError::SYSTEM_ERROR );\r
-}\r
-\r
-void RtApiOss :: callbackEvent()\r
-{\r
-  OssHandle *handle = (OssHandle *) stream_.apiHandle;\r
-  if ( stream_.state == STREAM_STOPPED ) {\r
-    MUTEX_LOCK( &stream_.mutex );\r
-    pthread_cond_wait( &handle->runnable, &stream_.mutex );\r
-    if ( stream_.state != STREAM_RUNNING ) {\r
-      MUTEX_UNLOCK( &stream_.mutex );\r
-      return;\r
-    }\r
-    MUTEX_UNLOCK( &stream_.mutex );\r
-  }\r
-\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtAudioError::WARNING );\r
-    return;\r
-  }\r
-\r
-  // Invoke user callback to get fresh output data.\r
-  int doStopStream = 0;\r
-  RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
-  double streamTime = getStreamTime();\r
-  RtAudioStreamStatus status = 0;\r
-  if ( stream_.mode != INPUT && handle->xrun[0] == true ) {\r
-    status |= RTAUDIO_OUTPUT_UNDERFLOW;\r
-    handle->xrun[0] = false;\r
-  }\r
-  if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {\r
-    status |= RTAUDIO_INPUT_OVERFLOW;\r
-    handle->xrun[1] = false;\r
-  }\r
-  doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
-                           stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );\r
-  if ( doStopStream == 2 ) {\r
-    this->abortStream();\r
-    return;\r
-  }\r
-\r
-  MUTEX_LOCK( &stream_.mutex );\r
-\r
-  // The state might change while waiting on a mutex.\r
-  if ( stream_.state == STREAM_STOPPED ) goto unlock;\r
-\r
-  int result;\r
-  char *buffer;\r
-  int samples;\r
-  RtAudioFormat format;\r
-\r
-  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Setup parameters and do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[0] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );\r
-      samples = stream_.bufferSize * stream_.nDeviceChannels[0];\r
-      format = stream_.deviceFormat[0];\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[0];\r
-      samples = stream_.bufferSize * stream_.nUserChannels[0];\r
-      format = stream_.userFormat;\r
-    }\r
-\r
-    // Do byte swapping if necessary.\r
-    if ( stream_.doByteSwap[0] )\r
-      byteSwapBuffer( buffer, samples, format );\r
-\r
-    if ( stream_.mode == DUPLEX && handle->triggered == false ) {\r
-      int trig = 0;\r
-      ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );\r
-      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
-      trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT;\r
-      ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );\r
-      handle->triggered = true;\r
-    }\r
-    else\r
-      // Write samples to device.\r
-      result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
-\r
-    if ( result == -1 ) {\r
-      // We'll assume this is an underrun, though there isn't a\r
-      // specific means for determining that.\r
-      handle->xrun[0] = true;\r
-      errorText_ = "RtApiOss::callbackEvent: audio write error.";\r
-      error( RtAudioError::WARNING );\r
-      // Continue on to input section.\r
-    }\r
-  }\r
-\r
-  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {\r
-\r
-    // Setup parameters.\r
-    if ( stream_.doConvertBuffer[1] ) {\r
-      buffer = stream_.deviceBuffer;\r
-      samples = stream_.bufferSize * stream_.nDeviceChannels[1];\r
-      format = stream_.deviceFormat[1];\r
-    }\r
-    else {\r
-      buffer = stream_.userBuffer[1];\r
-      samples = stream_.bufferSize * stream_.nUserChannels[1];\r
-      format = stream_.userFormat;\r
-    }\r
-\r
-    // Read samples from device.\r
-    result = read( handle->id[1], buffer, samples * formatBytes(format) );\r
-\r
-    if ( result == -1 ) {\r
-      // We'll assume this is an overrun, though there isn't a\r
-      // specific means for determining that.\r
-      handle->xrun[1] = true;\r
-      errorText_ = "RtApiOss::callbackEvent: audio read error.";\r
-      error( RtAudioError::WARNING );\r
-      goto unlock;\r
-    }\r
-\r
-    // Do byte swapping if necessary.\r
-    if ( stream_.doByteSwap[1] )\r
-      byteSwapBuffer( buffer, samples, format );\r
-\r
-    // Do buffer conversion if necessary.\r
-    if ( stream_.doConvertBuffer[1] )\r
-      convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );\r
-  }\r
-\r
- unlock:\r
-  MUTEX_UNLOCK( &stream_.mutex );\r
-\r
-  RtApi::tickStreamTime();\r
-  if ( doStopStream == 1 ) this->stopStream();\r
-}\r
-\r
-static void *ossCallbackHandler( void *ptr )\r
-{\r
-  CallbackInfo *info = (CallbackInfo *) ptr;\r
-  RtApiOss *object = (RtApiOss *) info->object;\r
-  bool *isRunning = &info->isRunning;\r
-\r
-  while ( *isRunning == true ) {\r
-    pthread_testcancel();\r
-    object->callbackEvent();\r
-  }\r
-\r
-  pthread_exit( NULL );\r
-}\r
-\r
-//******************** End of __LINUX_OSS__ *********************//\r
-#endif\r
-\r
-\r
-// *************************************************** //\r
-//\r
-// Protected common (OS-independent) RtAudio methods.\r
-//\r
-// *************************************************** //\r
-\r
-// This method can be modified to control the behavior of error\r
-// message printing.\r
-void RtApi :: error( RtAudioError::Type type )\r
-{\r
-  errorStream_.str(""); // clear the ostringstream\r
-\r
-  RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;\r
-  if ( errorCallback ) {\r
-    // abortStream() can generate new error messages. Ignore them. Just keep original one.\r
-\r
-    if ( firstErrorOccurred_ )\r
-      return;\r
-\r
-    firstErrorOccurred_ = true;\r
-    const std::string errorMessage = errorText_;\r
-\r
-    if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {\r
-      stream_.callbackInfo.isRunning = false; // exit from the thread\r
-      abortStream();\r
-    }\r
-\r
-    errorCallback( type, errorMessage );\r
-    firstErrorOccurred_ = false;\r
-    return;\r
-  }\r
-\r
-  if ( type == RtAudioError::WARNING && showWarnings_ == true )\r
-    std::cerr << '\n' << errorText_ << "\n\n";\r
-  else if ( type != RtAudioError::WARNING )\r
-    throw( RtAudioError( errorText_, type ) );\r
-}\r
-\r
-void RtApi :: verifyStream()\r
-{\r
-  if ( stream_.state == STREAM_CLOSED ) {\r
-    errorText_ = "RtApi:: a stream is not open!";\r
-    error( RtAudioError::INVALID_USE );\r
-  }\r
-}\r
-\r
-void RtApi :: clearStreamInfo()\r
-{\r
-  stream_.mode = UNINITIALIZED;\r
-  stream_.state = STREAM_CLOSED;\r
-  stream_.sampleRate = 0;\r
-  stream_.bufferSize = 0;\r
-  stream_.nBuffers = 0;\r
-  stream_.userFormat = 0;\r
-  stream_.userInterleaved = true;\r
-  stream_.streamTime = 0.0;\r
-  stream_.apiHandle = 0;\r
-  stream_.deviceBuffer = 0;\r
-  stream_.callbackInfo.callback = 0;\r
-  stream_.callbackInfo.userData = 0;\r
-  stream_.callbackInfo.isRunning = false;\r
-  stream_.callbackInfo.errorCallback = 0;\r
-  for ( int i=0; i<2; i++ ) {\r
-    stream_.device[i] = 11111;\r
-    stream_.doConvertBuffer[i] = false;\r
-    stream_.deviceInterleaved[i] = true;\r
-    stream_.doByteSwap[i] = false;\r
-    stream_.nUserChannels[i] = 0;\r
-    stream_.nDeviceChannels[i] = 0;\r
-    stream_.channelOffset[i] = 0;\r
-    stream_.deviceFormat[i] = 0;\r
-    stream_.latency[i] = 0;\r
-    stream_.userBuffer[i] = 0;\r
-    stream_.convertInfo[i].channels = 0;\r
-    stream_.convertInfo[i].inJump = 0;\r
-    stream_.convertInfo[i].outJump = 0;\r
-    stream_.convertInfo[i].inFormat = 0;\r
-    stream_.convertInfo[i].outFormat = 0;\r
-    stream_.convertInfo[i].inOffset.clear();\r
-    stream_.convertInfo[i].outOffset.clear();\r
-  }\r
-}\r
-\r
-unsigned int RtApi :: formatBytes( RtAudioFormat format )\r
-{\r
-  if ( format == RTAUDIO_SINT16 )\r
-    return 2;\r
-  else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )\r
-    return 4;\r
-  else if ( format == RTAUDIO_FLOAT64 )\r
-    return 8;\r
-  else if ( format == RTAUDIO_SINT24 )\r
-    return 3;\r
-  else if ( format == RTAUDIO_SINT8 )\r
-    return 1;\r
-\r
-  errorText_ = "RtApi::formatBytes: undefined format.";\r
-  error( RtAudioError::WARNING );\r
-\r
-  return 0;\r
-}\r
-\r
-void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel )\r
-{\r
-  if ( mode == INPUT ) { // convert device to user buffer\r
-    stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];\r
-    stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];\r
-    stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];\r
-    stream_.convertInfo[mode].outFormat = stream_.userFormat;\r
-  }\r
-  else { // convert user to device buffer\r
-    stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];\r
-    stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];\r
-    stream_.convertInfo[mode].inFormat = stream_.userFormat;\r
-    stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];\r
-  }\r
-\r
-  if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )\r
-    stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;\r
-  else\r
-    stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;\r
-\r
-  // Set up the interleave/deinterleave offsets.\r
-  if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) {\r
-    if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) ||\r
-         ( mode == INPUT && stream_.userInterleaved ) ) {\r
-      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
-        stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );\r
-        stream_.convertInfo[mode].outOffset.push_back( k );\r
-        stream_.convertInfo[mode].inJump = 1;\r
-      }\r
-    }\r
-    else {\r
-      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
-        stream_.convertInfo[mode].inOffset.push_back( k );\r
-        stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );\r
-        stream_.convertInfo[mode].outJump = 1;\r
-      }\r
-    }\r
-  }\r
-  else { // no (de)interleaving\r
-    if ( stream_.userInterleaved ) {\r
-      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
-        stream_.convertInfo[mode].inOffset.push_back( k );\r
-        stream_.convertInfo[mode].outOffset.push_back( k );\r
-      }\r
-    }\r
-    else {\r
-      for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {\r
-        stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );\r
-        stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );\r
-        stream_.convertInfo[mode].inJump = 1;\r
-        stream_.convertInfo[mode].outJump = 1;\r
-      }\r
-    }\r
-  }\r
-\r
-  // Add channel offset.\r
-  if ( firstChannel > 0 ) {\r
-    if ( stream_.deviceInterleaved[mode] ) {\r
-      if ( mode == OUTPUT ) {\r
-        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
-          stream_.convertInfo[mode].outOffset[k] += firstChannel;\r
-      }\r
-      else {\r
-        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
-          stream_.convertInfo[mode].inOffset[k] += firstChannel;\r
-      }\r
-    }\r
-    else {\r
-      if ( mode == OUTPUT ) {\r
-        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
-          stream_.convertInfo[mode].outOffset[k] += ( firstChannel * stream_.bufferSize );\r
-      }\r
-      else {\r
-        for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )\r
-          stream_.convertInfo[mode].inOffset[k] += ( firstChannel  * stream_.bufferSize );\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )\r
-{\r
-  // This function does format conversion, input/output channel compensation, and\r
-  // data interleaving/deinterleaving.  24-bit integers are assumed to occupy\r
-  // the lower three bytes of a 32-bit integer.\r
-\r
-  // Clear our device buffer when in/out duplex device channels are different\r
-  if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&\r
-       ( stream_.nDeviceChannels[0] < stream_.nDeviceChannels[1] ) )\r
-    memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );\r
-\r
-  int j;\r
-  if (info.outFormat == RTAUDIO_FLOAT64) {\r
-    Float64 scale;\r
-    Float64 *out = (Float64 *)outBuffer;\r
-\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      signed char *in = (signed char *)inBuffer;\r
-      scale = 1.0 / 127.5;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT16) {\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      scale = 1.0 / 32767.5;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      scale = 1.0 / 8388607.5;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      scale = 1.0 / 2147483647.5;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-  else if (info.outFormat == RTAUDIO_FLOAT32) {\r
-    Float32 scale;\r
-    Float32 *out = (Float32 *)outBuffer;\r
-\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      signed char *in = (signed char *)inBuffer;\r
-      scale = (Float32) ( 1.0 / 127.5 );\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT16) {\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      scale = (Float32) ( 1.0 / 32767.5 );\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      scale = (Float32) ( 1.0 / 8388607.5 );\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      scale = (Float32) ( 1.0 / 2147483647.5 );\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] += 0.5;\r
-          out[info.outOffset[j]] *= scale;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-  else if (info.outFormat == RTAUDIO_SINT32) {\r
-    Int32 *out = (Int32 *)outBuffer;\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      signed char *in = (signed char *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] <<= 24;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT16) {\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] <<= 16;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();\r
-          out[info.outOffset[j]] <<= 8;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-  else if (info.outFormat == RTAUDIO_SINT24) {\r
-    Int24 *out = (Int24 *)outBuffer;\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      signed char *in = (signed char *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);\r
-          //out[info.outOffset[j]] <<= 16;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT16) {\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);\r
-          //out[info.outOffset[j]] <<= 8;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);\r
-          //out[info.outOffset[j]] >>= 8;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-  else if (info.outFormat == RTAUDIO_SINT16) {\r
-    Int16 *out = (Int16 *)outBuffer;\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      signed char *in = (signed char *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];\r
-          out[info.outOffset[j]] <<= 8;\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT16) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-  else if (info.outFormat == RTAUDIO_SINT8) {\r
-    signed char *out = (signed char *)outBuffer;\r
-    if (info.inFormat == RTAUDIO_SINT8) {\r
-      // Channel compensation and/or (de)interleaving only.\r
-      signed char *in = (signed char *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = in[info.inOffset[j]];\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    if (info.inFormat == RTAUDIO_SINT16) {\r
-      Int16 *in = (Int16 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT24) {\r
-      Int24 *in = (Int24 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_SINT32) {\r
-      Int32 *in = (Int32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT32) {\r
-      Float32 *in = (Float32 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-    else if (info.inFormat == RTAUDIO_FLOAT64) {\r
-      Float64 *in = (Float64 *)inBuffer;\r
-      for (unsigned int i=0; i<stream_.bufferSize; i++) {\r
-        for (j=0; j<info.channels; j++) {\r
-          out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);\r
-        }\r
-        in += info.inJump;\r
-        out += info.outJump;\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-//static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }\r
-//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }\r
-//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }\r
-\r
-void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )\r
-{\r
-  register char val;\r
-  register char *ptr;\r
-\r
-  ptr = buffer;\r
-  if ( format == RTAUDIO_SINT16 ) {\r
-    for ( unsigned int i=0; i<samples; i++ ) {\r
-      // Swap 1st and 2nd bytes.\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+1);\r
-      *(ptr+1) = val;\r
-\r
-      // Increment 2 bytes.\r
-      ptr += 2;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_SINT32 ||\r
-            format == RTAUDIO_FLOAT32 ) {\r
-    for ( unsigned int i=0; i<samples; i++ ) {\r
-      // Swap 1st and 4th bytes.\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+3);\r
-      *(ptr+3) = val;\r
-\r
-      // Swap 2nd and 3rd bytes.\r
-      ptr += 1;\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+1);\r
-      *(ptr+1) = val;\r
-\r
-      // Increment 3 more bytes.\r
-      ptr += 3;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_SINT24 ) {\r
-    for ( unsigned int i=0; i<samples; i++ ) {\r
-      // Swap 1st and 3rd bytes.\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+2);\r
-      *(ptr+2) = val;\r
-\r
-      // Increment 2 more bytes.\r
-      ptr += 2;\r
-    }\r
-  }\r
-  else if ( format == RTAUDIO_FLOAT64 ) {\r
-    for ( unsigned int i=0; i<samples; i++ ) {\r
-      // Swap 1st and 8th bytes\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+7);\r
-      *(ptr+7) = val;\r
-\r
-      // Swap 2nd and 7th bytes\r
-      ptr += 1;\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+5);\r
-      *(ptr+5) = val;\r
-\r
-      // Swap 3rd and 6th bytes\r
-      ptr += 1;\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+3);\r
-      *(ptr+3) = val;\r
-\r
-      // Swap 4th and 5th bytes\r
-      ptr += 1;\r
-      val = *(ptr);\r
-      *(ptr) = *(ptr+1);\r
-      *(ptr+1) = val;\r
-\r
-      // Increment 5 more bytes.\r
-      ptr += 5;\r
-    }\r
-  }\r
-}\r
-\r
-  // Indentation settings for Vim and Emacs\r
-  //\r
-  // Local Variables:\r
-  // c-basic-offset: 2\r
-  // indent-tabs-mode: nil\r
-  // End:\r
-  //\r
-  // vim: et sts=2 sw=2\r
-\r
diff --git a/src/rtaudio-mod/RtAudio.h b/src/rtaudio-mod/RtAudio.h
deleted file mode 100644 (file)
index a3534ad..0000000
+++ /dev/null
@@ -1,1177 +0,0 @@
-/************************************************************************/
-/*! \class RtAudio
-    \brief Realtime audio i/o C++ classes.
-
-    RtAudio provides a common API (Application Programming Interface)
-    for realtime audio input/output across Linux (native ALSA, Jack,
-    and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
-    (DirectSound, ASIO and WASAPI) operating systems.
-
-    RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
-
-    RtAudio: realtime audio i/o C++ classes
-    Copyright (c) 2001-2014 Gary P. Scavone
-
-    Permission is hereby granted, free of charge, to any person
-    obtaining a copy of this software and associated documentation files
-    (the "Software"), to deal in the Software without restriction,
-    including without limitation the rights to use, copy, modify, merge,
-    publish, distribute, sublicense, and/or sell copies of the Software,
-    and to permit persons to whom the Software is furnished to do so,
-    subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be
-    included in all copies or substantial portions of the Software.
-
-    Any person wishing to distribute modifications to the Software is
-    asked to send the modifications to the original developer so that
-    they can be incorporated into the canonical version.  This is,
-    however, not a binding provision of this license.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
-    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-/************************************************************************/
-
-/*!
-  \file RtAudio.h
- */
-
-#ifndef __RTAUDIO_H
-#define __RTAUDIO_H
-
-#define RTAUDIO_VERSION "4.1.1"
-
-#include <string>
-#include <vector>
-
-/* --- Monocasual hack ---------------------------------------------- */
-#if defined(__linux__)
-#include <jack/jack.h>
-#endif
-/* ------------------------------------------------------------------ */
-
-#include <exception>
-#include <iostream>
-
-/*! \typedef typedef unsigned long RtAudioFormat;
-    \brief RtAudio data format type.
-
-    Support for signed integers and floats.  Audio data fed to/from an
-    RtAudio stream is assumed to ALWAYS be in host byte order.  The
-    internal routines will automatically take care of any necessary
-    byte-swapping between the host format and the soundcard.  Thus,
-    endian-ness is not a concern in the following format definitions.
-
-    - \e RTAUDIO_SINT8:   8-bit signed integer.
-    - \e RTAUDIO_SINT16:  16-bit signed integer.
-    - \e RTAUDIO_SINT24:  24-bit signed integer.
-    - \e RTAUDIO_SINT32:  32-bit signed integer.
-    - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0.
-    - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
-*/
-typedef unsigned long RtAudioFormat;
-static const RtAudioFormat RTAUDIO_SINT8 = 0x1;    // 8-bit signed integer.
-static const RtAudioFormat RTAUDIO_SINT16 = 0x2;   // 16-bit signed integer.
-static const RtAudioFormat RTAUDIO_SINT24 = 0x4;   // 24-bit signed integer.
-static const RtAudioFormat RTAUDIO_SINT32 = 0x8;   // 32-bit signed integer.
-static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0.
-static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0.
-
-/*! \typedef typedef unsigned long RtAudioStreamFlags;
-    \brief RtAudio stream option flags.
-
-    The following flags can be OR'ed together to allow a client to
-    make changes to the default stream behavior:
-
-    - \e RTAUDIO_NONINTERLEAVED:   Use non-interleaved buffers (default = interleaved).
-    - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
-    - \e RTAUDIO_HOG_DEVICE:       Attempt grab device for exclusive use.
-    - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
-
-    By default, RtAudio streams pass and receive audio data from the
-    client in an interleaved format.  By passing the
-    RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio
-    data will instead be presented in non-interleaved buffers.  In
-    this case, each buffer argument in the RtAudioCallback function
-    will point to a single array of data, with \c nFrames samples for
-    each channel concatenated back-to-back.  For example, the first
-    sample of data for the second channel would be located at index \c
-    nFrames (assuming the \c buffer pointer was recast to the correct
-    data type for the stream).
-
-    Certain audio APIs offer a number of parameters that influence the
-    I/O latency of a stream.  By default, RtAudio will attempt to set
-    these parameters internally for robust (glitch-free) performance
-    (though some APIs, like Windows Direct Sound, make this difficult).
-    By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
-    function, internal stream settings will be influenced in an attempt
-    to minimize stream latency, though possibly at the expense of stream
-    performance.
-
-    If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to
-    open the input and/or output stream device(s) for exclusive use.
-    Note that this is not possible with all supported audio APIs.
-
-    If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 
-    to select realtime scheduling (round-robin) for the callback thread.
-
-    If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
-    open the "default" PCM device when using the ALSA API. Note that this
-    will override any specified input or output device id.
-*/
-typedef unsigned int RtAudioStreamFlags;
-static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1;    // Use non-interleaved buffers (default = interleaved).
-static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2;  // Attempt to set stream parameters for lowest possible latency.
-static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4;        // Attempt grab device and prevent use by others.
-static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread.
-static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only).
-
-/*! \typedef typedef unsigned long RtAudioStreamStatus;
-    \brief RtAudio stream status (over- or underflow) flags.
-
-    Notification of a stream over- or underflow is indicated by a
-    non-zero stream \c status argument in the RtAudioCallback function.
-    The stream status can be one of the following two options,
-    depending on whether the stream is open for output and/or input:
-
-    - \e RTAUDIO_INPUT_OVERFLOW:   Input data was discarded because of an overflow condition at the driver.
-    - \e RTAUDIO_OUTPUT_UNDERFLOW: The output buffer ran low, likely producing a break in the output sound.
-*/
-typedef unsigned int RtAudioStreamStatus;
-static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1;    // Input data was discarded because of an overflow condition at the driver.
-static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2;  // The output buffer ran low, likely causing a gap in the output sound.
-
-//! RtAudio callback function prototype.
-/*!
-   All RtAudio clients must create a function of type RtAudioCallback
-   to read and/or write data from/to the audio stream.  When the
-   underlying audio system is ready for new input or output data, this
-   function will be invoked.
-
-   \param outputBuffer For output (or duplex) streams, the client
-          should write \c nFrames of audio sample frames into this
-          buffer.  This argument should be recast to the datatype
-          specified when the stream was opened.  For input-only
-          streams, this argument will be NULL.
-
-   \param inputBuffer For input (or duplex) streams, this buffer will
-          hold \c nFrames of input audio sample frames.  This
-          argument should be recast to the datatype specified when the
-          stream was opened.  For output-only streams, this argument
-          will be NULL.
-
-   \param nFrames The number of sample frames of input or output
-          data in the buffers.  The actual buffer size in bytes is
-          dependent on the data type and number of channels in use.
-
-   \param streamTime The number of seconds that have elapsed since the
-          stream was started.
-
-   \param status If non-zero, this argument indicates a data overflow
-          or underflow condition for the stream.  The particular
-          condition can be determined by comparison with the
-          RtAudioStreamStatus flags.
-
-   \param userData A pointer to optional data provided by the client
-          when opening the stream (default = NULL).
-
-   To continue normal stream operation, the RtAudioCallback function
-   should return a value of zero.  To stop the stream and drain the
-   output buffer, the function should return a value of one.  To abort
-   the stream immediately, the client should return a value of two.
- */
-typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
-                                unsigned int nFrames,
-                                double streamTime,
-                                RtAudioStreamStatus status,
-                                void *userData );
-
-/************************************************************************/
-/*! \class RtAudioError
-    \brief Exception handling class for RtAudio.
-
-    The RtAudioError class is quite simple but it does allow errors to be
-    "caught" by RtAudioError::Type. See the RtAudio documentation to know
-    which methods can throw an RtAudioError.
-*/
-/************************************************************************/
-
-class RtAudioError : public std::exception
-{
- public:
-  //! Defined RtAudioError types.
-  enum Type {
-    WARNING,           /*!< A non-critical error. */
-    DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
-    UNSPECIFIED,       /*!< The default, unspecified error type. */
-    NO_DEVICES_FOUND,  /*!< No devices found on system. */
-    INVALID_DEVICE,    /*!< An invalid device ID was specified. */
-    MEMORY_ERROR,      /*!< An error occured during memory allocation. */
-    INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
-    INVALID_USE,       /*!< The function was called incorrectly. */
-    DRIVER_ERROR,      /*!< A system driver error occured. */
-    SYSTEM_ERROR,      /*!< A system error occured. */
-    THREAD_ERROR       /*!< A thread error occured. */
-  };
-
-  //! The constructor.
-  RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
-  //! The destructor.
-  virtual ~RtAudioError( void ) throw() {}
-
-  //! Prints thrown error message to stderr.
-  virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
-
-  //! Returns the thrown error message type.
-  virtual const Type& getType(void) const throw() { return type_; }
-
-  //! Returns the thrown error message string.
-  virtual const std::string& getMessage(void) const throw() { return message_; }
-
-  //! Returns the thrown error message as a c-style string.
-  virtual const char* what( void ) const throw() { return message_.c_str(); }
-
- protected:
-  std::string message_;
-  Type type_;
-};
-
-//! RtAudio error callback function prototype.
-/*!
-    \param type Type of error.
-    \param errorText Error description.
- */
-typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText );
-
-// **************************************************************** //
-//
-// RtAudio class declaration.
-//
-// RtAudio is a "controller" used to select an available audio i/o
-// interface.  It presents a common API for the user to call but all
-// functionality is implemented by the class RtApi and its
-// subclasses.  RtAudio creates an instance of an RtApi subclass
-// based on the user's API choice.  If no choice is made, RtAudio
-// attempts to make a "logical" API selection.
-//
-// **************************************************************** //
-
-class RtApi;
-
-class RtAudio
-{
- public:
-
-  //! Audio API specifier arguments.
-  enum Api {
-    UNSPECIFIED,    /*!< Search for a working compiled API. */
-    LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
-    LINUX_PULSE,    /*!< The Linux PulseAudio API. */
-    LINUX_OSS,      /*!< The Linux Open Sound System API. */
-    UNIX_JACK,      /*!< The Jack Low-Latency Audio Server API. */
-    MACOSX_CORE,    /*!< Macintosh OS-X Core Audio API. */
-    WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
-    WINDOWS_ASIO,   /*!< The Steinberg Audio Stream I/O API. */
-    WINDOWS_DS,     /*!< The Microsoft Direct Sound API. */
-    RTAUDIO_DUMMY   /*!< A compilable but non-functional API. */
-  };
-
-  //! The public device information structure for returning queried values.
-  struct DeviceInfo {
-    bool probed;                  /*!< true if the device capabilities were successfully probed. */
-    std::string name;             /*!< Character string device identifier. */
-    unsigned int outputChannels;  /*!< Maximum output channels supported by device. */
-    unsigned int inputChannels;   /*!< Maximum input channels supported by device. */
-    unsigned int duplexChannels;  /*!< Maximum simultaneous input/output channels supported by device. */
-    bool isDefaultOutput;         /*!< true if this is the default output device. */
-    bool isDefaultInput;          /*!< true if this is the default input device. */
-    std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
-    RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
-
-    // Default constructor.
-    DeviceInfo()
-      :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
-       isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
-  };
-
-  //! The structure for specifying input or ouput stream parameters.
-  struct StreamParameters {
-    unsigned int deviceId;     /*!< Device index (0 to getDeviceCount() - 1). */
-    unsigned int nChannels;    /*!< Number of channels. */
-    unsigned int firstChannel; /*!< First channel index on device (default = 0). */
-
-    // Default constructor.
-    StreamParameters()
-      : deviceId(0), nChannels(0), firstChannel(0) {}
-  };
-
-  //! The structure for specifying stream options.
-  /*!
-    The following flags can be OR'ed together to allow a client to
-    make changes to the default stream behavior:
-
-    - \e RTAUDIO_NONINTERLEAVED:    Use non-interleaved buffers (default = interleaved).
-    - \e RTAUDIO_MINIMIZE_LATENCY:  Attempt to set stream parameters for lowest possible latency.
-    - \e RTAUDIO_HOG_DEVICE:        Attempt grab device for exclusive use.
-    - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread.
-    - \e RTAUDIO_ALSA_USE_DEFAULT:  Use the "default" PCM device (ALSA only).
-
-    By default, RtAudio streams pass and receive audio data from the
-    client in an interleaved format.  By passing the
-    RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio
-    data will instead be presented in non-interleaved buffers.  In
-    this case, each buffer argument in the RtAudioCallback function
-    will point to a single array of data, with \c nFrames samples for
-    each channel concatenated back-to-back.  For example, the first
-    sample of data for the second channel would be located at index \c
-    nFrames (assuming the \c buffer pointer was recast to the correct
-    data type for the stream).
-
-    Certain audio APIs offer a number of parameters that influence the
-    I/O latency of a stream.  By default, RtAudio will attempt to set
-    these parameters internally for robust (glitch-free) performance
-    (though some APIs, like Windows Direct Sound, make this difficult).
-    By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
-    function, internal stream settings will be influenced in an attempt
-    to minimize stream latency, though possibly at the expense of stream
-    performance.
-
-    If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to
-    open the input and/or output stream device(s) for exclusive use.
-    Note that this is not possible with all supported audio APIs.
-
-    If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 
-    to select realtime scheduling (round-robin) for the callback thread.
-    The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME
-    flag is set. It defines the thread's realtime priority.
-
-    If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
-    open the "default" PCM device when using the ALSA API. Note that this
-    will override any specified input or output device id.
-
-    The \c numberOfBuffers parameter can be used to control stream
-    latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs
-    only.  A value of two is usually the smallest allowed.  Larger
-    numbers can potentially result in more robust stream performance,
-    though likely at the cost of stream latency.  The value set by the
-    user is replaced during execution of the RtAudio::openStream()
-    function by the value actually used by the system.
-
-    The \c streamName parameter can be used to set the client name
-    when using the Jack API.  By default, the client name is set to
-    RtApiJack.  However, if you wish to create multiple instances of
-    RtAudio with Jack, each instance must have a unique client name.
-  */
-  struct StreamOptions {
-    RtAudioStreamFlags flags;      /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */
-    unsigned int numberOfBuffers;  /*!< Number of stream buffers. */
-    std::string streamName;        /*!< A stream name (currently used only in Jack). */
-    int priority;                  /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */
-
-    // Default constructor.
-    StreamOptions()
-    : flags(0), numberOfBuffers(0), priority(0) {}
-  };
-
-  //! A static function to determine the current RtAudio version.
-  static std::string getVersion( void ) throw();
-
-  //! A static function to determine the available compiled audio APIs.
-  /*!
-    The values returned in the std::vector can be compared against
-    the enumerated list values.  Note that there can be more than one
-    API compiled for certain operating systems.
-  */
-  static void getCompiledApi( std::vector<RtAudio::Api> &apis ) throw();
-
-  //! The class constructor.
-  /*!
-    The constructor performs minor initialization tasks.  An exception
-    can be thrown if no API support is compiled.
-
-    If no API argument is specified and multiple API support has been
-    compiled, the default order of use is JACK, ALSA, OSS (Linux
-    systems) and ASIO, DS (Windows systems).
-  */
-  RtAudio( RtAudio::Api api=UNSPECIFIED );
-
-  //! The destructor.
-  /*!
-    If a stream is running or open, it will be stopped and closed
-    automatically.
-  */
-  ~RtAudio() throw();
-
-  //! Returns the audio API specifier for the current instance of RtAudio.
-  RtAudio::Api getCurrentApi( void ) throw();
-
-  //! A public function that queries for the number of audio devices available.
-  /*!
-    This function performs a system query of available devices each time it
-    is called, thus supporting devices connected \e after instantiation. If
-    a system error occurs during processing, a warning will be issued. 
-  */
-  unsigned int getDeviceCount( void ) throw();
-
-  //! Return an RtAudio::DeviceInfo structure for a specified device number.
-  /*!
-
-    Any device integer between 0 and getDeviceCount() - 1 is valid.
-    If an invalid argument is provided, an RtAudioError (type = INVALID_USE)
-    will be thrown.  If a device is busy or otherwise unavailable, the
-    structure member "probed" will have a value of "false" and all
-    other members are undefined.  If the specified device is the
-    current default input or output device, the corresponding
-    "isDefault" member will have a value of "true".
-  */
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-
-  //! A function that returns the index of the default output device.
-  /*!
-    If the underlying audio API does not provide a "default
-    device", or if no devices are available, the return value will be
-    0.  Note that this is a valid device identifier and it is the
-    client's responsibility to verify that a device is available
-    before attempting to open a stream.
-  */
-  unsigned int getDefaultOutputDevice( void ) throw();
-
-  //! A function that returns the index of the default input device.
-  /*!
-    If the underlying audio API does not provide a "default
-    device", or if no devices are available, the return value will be
-    0.  Note that this is a valid device identifier and it is the
-    client's responsibility to verify that a device is available
-    before attempting to open a stream.
-  */
-  unsigned int getDefaultInputDevice( void ) throw();
-
-  //! A public function for opening a stream with the specified parameters.
-  /*!
-    An RtAudioError (type = SYSTEM_ERROR) is thrown if a stream cannot be
-    opened with the specified parameters or an error occurs during
-    processing.  An RtAudioError (type = INVALID_USE) is thrown if any
-    invalid device ID or channel number parameters are specified.
-
-    \param outputParameters Specifies output stream parameters to use
-           when opening a stream, including a device ID, number of channels,
-           and starting channel number.  For input-only streams, this
-           argument should be NULL.  The device ID is an index value between
-           0 and getDeviceCount() - 1.
-    \param inputParameters Specifies input stream parameters to use
-           when opening a stream, including a device ID, number of channels,
-           and starting channel number.  For output-only streams, this
-           argument should be NULL.  The device ID is an index value between
-           0 and getDeviceCount() - 1.
-    \param format An RtAudioFormat specifying the desired sample data format.
-    \param sampleRate The desired sample rate (sample frames per second).
-    \param *bufferFrames A pointer to a value indicating the desired
-           internal buffer size in sample frames.  The actual value
-           used by the device is returned via the same pointer.  A
-           value of zero can be specified, in which case the lowest
-           allowable value is determined.
-    \param callback A client-defined function that will be invoked
-           when input data is available and/or output data is needed.
-    \param userData An optional pointer to data that can be accessed
-           from within the callback function.
-    \param options An optional pointer to a structure containing various
-           global stream options, including a list of OR'ed RtAudioStreamFlags
-           and a suggested number of stream buffers that can be used to 
-           control stream latency.  More buffers typically result in more
-           robust performance, though at a cost of greater latency.  If a
-           value of zero is specified, a system-specific median value is
-           chosen.  If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the
-           lowest allowable value is used.  The actual value used is
-           returned via the structure argument.  The parameter is API dependent.
-    \param errorCallback A client-defined function that will be invoked
-           when an error has occured.
-  */
-  void openStream( RtAudio::StreamParameters *outputParameters,
-                   RtAudio::StreamParameters *inputParameters,
-                   RtAudioFormat format, unsigned int sampleRate,
-                   unsigned int *bufferFrames, RtAudioCallback callback,
-                   void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL );
-
-  //! A function that closes a stream and frees any associated stream memory.
-  /*!
-    If a stream is not open, this function issues a warning and
-    returns (no exception is thrown).
-  */
-  void closeStream( void ) throw();
-
-  //! A function that starts a stream.
-  /*!
-    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
-    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
-    stream is not open.  A warning is issued if the stream is already
-    running.
-  */
-  void startStream( void );
-
-  //! Stop a stream, allowing any samples remaining in the output queue to be played.
-  /*!
-    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
-    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
-    stream is not open.  A warning is issued if the stream is already
-    stopped.
-  */
-  void stopStream( void );
-
-  //! Stop a stream, discarding any samples remaining in the input/output queue.
-  /*!
-    An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs
-    during processing.  An RtAudioError (type = INVALID_USE) is thrown if a
-    stream is not open.  A warning is issued if the stream is already
-    stopped.
-  */
-  void abortStream( void );
-
-  //! Returns true if a stream is open and false if not.
-  bool isStreamOpen( void ) const throw();
-
-  //! Returns true if the stream is running and false if it is stopped or not open.
-  bool isStreamRunning( void ) const throw();
-
-  //! Returns the number of elapsed seconds since the stream was started.
-  /*!
-    If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
-  */
-  double getStreamTime( void );
-
-  //! Set the stream time to a time in seconds greater than or equal to 0.0.
-  /*!
-    If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown.
-  */
-  void setStreamTime( double time );
-
-  //! Returns the internal stream latency in sample frames.
-  /*!
-    The stream latency refers to delay in audio input and/or output
-    caused by internal buffering by the audio system and/or hardware.
-    For duplex streams, the returned value will represent the sum of
-    the input and output latencies.  If a stream is not open, an
-    RtAudioError (type = INVALID_USE) will be thrown.  If the API does not
-    report latency, the return value will be zero.
-  */
-  long getStreamLatency( void );
-
- //! Returns actual sample rate in use by the stream.
- /*!
-   On some systems, the sample rate used may be slightly different
-   than that specified in the stream parameters.  If a stream is not
-   open, an RtAudioError (type = INVALID_USE) will be thrown.
- */
-  unsigned int getStreamSampleRate( void );
-
-  //! Specify whether warning messages should be printed to stderr.
-  void showWarnings( bool value = true ) throw();
-  
-/* --- Monocasual hack ---------------------------------------------- */
-       //protected:
-/* ------------------------------------------------------------------ */
-
-  void openRtApi( RtAudio::Api api );
-  RtApi *rtapi_;
-};
-
-// Operating system dependent thread functionality.
-#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
-
-  #ifndef NOMINMAX
-    #define NOMINMAX
-  #endif
-  #include <windows.h>
-  #include <process.h>
-
-  typedef uintptr_t ThreadHandle;
-  typedef CRITICAL_SECTION StreamMutex;
-
-#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
-  // Using pthread library for various flavors of unix.
-  #include <pthread.h>
-
-  typedef pthread_t ThreadHandle;
-  typedef pthread_mutex_t StreamMutex;
-
-#else // Setup for "dummy" behavior
-
-  #define __RTAUDIO_DUMMY__
-  typedef int ThreadHandle;
-  typedef int StreamMutex;
-
-#endif
-
-// This global structure type is used to pass callback information
-// between the private RtAudio stream structure and global callback
-// handling functions.
-struct CallbackInfo {
-  void *object;    // Used as a "this" pointer.
-  ThreadHandle thread;
-  void *callback;
-  void *userData;
-  void *errorCallback;
-  void *apiInfo;   // void pointer for API specific callback information
-  bool isRunning;
-  bool doRealtime;
-  int priority;
-
-  // Default constructor.
-  CallbackInfo()
-  :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {}
-};
-
-// **************************************************************** //
-//
-// RtApi class declaration.
-//
-// Subclasses of RtApi contain all API- and OS-specific code necessary
-// to fully implement the RtAudio API.
-//
-// Note that RtApi is an abstract base class and cannot be
-// explicitly instantiated.  The class RtAudio will create an
-// instance of an RtApi subclass (RtApiOss, RtApiAlsa,
-// RtApiJack, RtApiCore, RtApiDs, or RtApiAsio).
-//
-// **************************************************************** //
-
-#pragma pack(push, 1)
-class S24 {
-
- protected:
-  unsigned char c3[3];
-
- public:
-  S24() {}
-
-  S24& operator = ( const int& i ) {
-    c3[0] = (i & 0x000000ff);
-    c3[1] = (i & 0x0000ff00) >> 8;
-    c3[2] = (i & 0x00ff0000) >> 16;
-    return *this;
-  }
-
-  S24( const S24& v ) { *this = v; }
-  S24( const double& d ) { *this = (int) d; }
-  S24( const float& f ) { *this = (int) f; }
-  S24( const signed short& s ) { *this = (int) s; }
-  S24( const char& c ) { *this = (int) c; }
-
-  int asInt() {
-    int i = c3[0] | (c3[1] << 8) | (c3[2] << 16);
-    if (i & 0x800000) i |= ~0xffffff;
-    return i;
-  }
-};
-#pragma pack(pop)
-
-#if defined( HAVE_GETTIMEOFDAY )
-  #include <sys/time.h>
-#endif
-
-#include <sstream>
-
-class RtApi
-{
-public:
-
-/* --- Monocasual hack ---------------------------------------------- */
-#ifdef __linux__
-       void *__HACK__getJackClient();
-#endif
-/* ------------------------------------------------------------------ */
-
-  RtApi();
-  virtual ~RtApi();
-  virtual RtAudio::Api getCurrentApi( void ) = 0;
-  virtual unsigned int getDeviceCount( void ) = 0;
-  virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0;
-  virtual unsigned int getDefaultInputDevice( void );
-  virtual unsigned int getDefaultOutputDevice( void );
-  void openStream( RtAudio::StreamParameters *outputParameters,
-                   RtAudio::StreamParameters *inputParameters,
-                   RtAudioFormat format, unsigned int sampleRate,
-                   unsigned int *bufferFrames, RtAudioCallback callback,
-                   void *userData, RtAudio::StreamOptions *options,
-                   RtAudioErrorCallback errorCallback );
-  virtual void closeStream( void );
-  virtual void startStream( void ) = 0;
-  virtual void stopStream( void ) = 0;
-  virtual void abortStream( void ) = 0;
-  long getStreamLatency( void );
-  unsigned int getStreamSampleRate( void );
-  virtual double getStreamTime( void );
-  virtual void setStreamTime( double time );
-  bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }
-  bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }
-  void showWarnings( bool value ) { showWarnings_ = value; }
-
-
-protected:
-
-  static const unsigned int MAX_SAMPLE_RATES;
-  static const unsigned int SAMPLE_RATES[];
-
-  enum { FAILURE, SUCCESS };
-
-  enum StreamState {
-    STREAM_STOPPED,
-    STREAM_STOPPING,
-    STREAM_RUNNING,
-    STREAM_CLOSED = -50
-  };
-
-  enum StreamMode {
-    OUTPUT,
-    INPUT,
-    DUPLEX,
-    UNINITIALIZED = -75
-  };
-
-  // A protected structure used for buffer conversion.
-  struct ConvertInfo {
-    int channels;
-    int inJump, outJump;
-    RtAudioFormat inFormat, outFormat;
-    std::vector<int> inOffset;
-    std::vector<int> outOffset;
-  };
-
-  // A protected structure for audio streams.
-  struct RtApiStream {
-    unsigned int device[2];    // Playback and record, respectively.
-    void *apiHandle;           // void pointer for API specific stream handle information
-    StreamMode mode;           // OUTPUT, INPUT, or DUPLEX.
-    StreamState state;         // STOPPED, RUNNING, or CLOSED
-    char *userBuffer[2];       // Playback and record, respectively.
-    char *deviceBuffer;
-    bool doConvertBuffer[2];   // Playback and record, respectively.
-    bool userInterleaved;
-    bool deviceInterleaved[2]; // Playback and record, respectively.
-    bool doByteSwap[2];        // Playback and record, respectively.
-    unsigned int sampleRate;
-    unsigned int bufferSize;
-    unsigned int nBuffers;
-    unsigned int nUserChannels[2];    // Playback and record, respectively.
-    unsigned int nDeviceChannels[2];  // Playback and record channels, respectively.
-    unsigned int channelOffset[2];    // Playback and record, respectively.
-    unsigned long latency[2];         // Playback and record, respectively.
-    RtAudioFormat userFormat;
-    RtAudioFormat deviceFormat[2];    // Playback and record, respectively.
-    StreamMutex mutex;
-    CallbackInfo callbackInfo;
-    ConvertInfo convertInfo[2];
-    double streamTime;         // Number of elapsed seconds since the stream started.
-
-#if defined(HAVE_GETTIMEOFDAY)
-    struct timeval lastTickTimestamp;
-#endif
-
-    RtApiStream()
-      :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; }
-  };
-
-  typedef S24 Int24;
-  typedef signed short Int16;
-  typedef signed int Int32;
-  typedef float Float32;
-  typedef double Float64;
-
-  std::ostringstream errorStream_;
-  std::string errorText_;
-  bool showWarnings_;
-  RtApiStream stream_;
-  bool firstErrorOccurred_;
-
-  /*!
-    Protected, api-specific method that attempts to open a device
-    with the given parameters.  This function MUST be implemented by
-    all subclasses.  If an error is encountered during the probe, a
-    "warning" message is reported and FAILURE is returned. A
-    successful probe is indicated by a return value of SUCCESS.
-  */
-  virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                                unsigned int firstChannel, unsigned int sampleRate,
-                                RtAudioFormat format, unsigned int *bufferSize,
-                                RtAudio::StreamOptions *options );
-
-  //! A protected function used to increment the stream time.
-  void tickStreamTime( void );
-
-  //! Protected common method to clear an RtApiStream structure.
-  void clearStreamInfo();
-
-  /*!
-    Protected common method that throws an RtAudioError (type =
-    INVALID_USE) if a stream is not open.
-  */
-  void verifyStream( void );
-
-  //! Protected common error method to allow global control over error handling.
-  void error( RtAudioError::Type type );
-
-  /*!
-    Protected method used to perform format, channel number, and/or interleaving
-    conversions between the user and device buffers.
-  */
-  void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info );
-
-  //! Protected common method used to perform byte-swapping on buffers.
-  void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format );
-
-  //! Protected common method that returns the number of bytes for a given format.
-  unsigned int formatBytes( RtAudioFormat format );
-
-  //! Protected common method that sets up the parameters for buffer conversion.
-  void setConvertInfo( StreamMode mode, unsigned int firstChannel );
-};
-
-// **************************************************************** //
-//
-// Inline RtAudio definitions.
-//
-// **************************************************************** //
-
-inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
-inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); }
-inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
-inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); }
-inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); }
-inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); }
-inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
-inline void RtAudio :: stopStream( void )  { return rtapi_->stopStream(); }
-inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
-inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
-inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
-inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
-inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
-inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
-inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); }
-inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
-
-// RtApi Subclass prototypes.
-
-#if defined(__MACOSX_CORE__)
-
-#include <CoreAudio/AudioHardware.h>
-
-class RtApiCore: public RtApi
-{
-public:
-
-  RtApiCore();
-  ~RtApiCore();
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  unsigned int getDefaultOutputDevice( void );
-  unsigned int getDefaultInputDevice( void );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-  long getStreamLatency( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  bool callbackEvent( AudioDeviceID deviceId,
-                      const AudioBufferList *inBufferList,
-                      const AudioBufferList *outBufferList );
-
-  private:
-
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-  static const char* getErrorCode( OSStatus code );
-};
-
-#endif
-
-#if defined(__UNIX_JACK__)
-
-class RtApiJack: public RtApi
-{
-public:
-
-  RtApiJack();
-  ~RtApiJack();
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-  long getStreamLatency( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  bool callbackEvent( unsigned long nframes );
-
-  private:
-
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__WINDOWS_ASIO__)
-
-class RtApiAsio: public RtApi
-{
-public:
-
-  RtApiAsio();
-  ~RtApiAsio();
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-  long getStreamLatency( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  bool callbackEvent( long bufferIndex );
-
-  private:
-
-  std::vector<RtAudio::DeviceInfo> devices_;
-  void saveDeviceInfo( void );
-  bool coInitialized_;
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__WINDOWS_DS__)
-
-class RtApiDs: public RtApi
-{
-public:
-
-  RtApiDs();
-  ~RtApiDs();
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
-  unsigned int getDeviceCount( void );
-  unsigned int getDefaultOutputDevice( void );
-  unsigned int getDefaultInputDevice( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-  long getStreamLatency( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  void callbackEvent( void );
-
-  private:
-
-  bool coInitialized_;
-  bool buffersRolling;
-  long duplexPrerollBytes;
-  std::vector<struct DsDevice> dsDevices;
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__WINDOWS_WASAPI__)
-
-struct IMMDeviceEnumerator;
-
-class RtApiWasapi : public RtApi
-{
-public:
-  RtApiWasapi();
-  ~RtApiWasapi();
-
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  unsigned int getDefaultOutputDevice( void );
-  unsigned int getDefaultInputDevice( void );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-
-private:
-  bool coInitialized_;
-  IMMDeviceEnumerator* deviceEnumerator_;
-
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int* bufferSize,
-                        RtAudio::StreamOptions* options );
-
-  static DWORD WINAPI runWasapiThread( void* wasapiPtr );
-  static DWORD WINAPI stopWasapiThread( void* wasapiPtr );
-  static DWORD WINAPI abortWasapiThread( void* wasapiPtr );
-  void wasapiThread();
-};
-
-#endif
-
-#if defined(__LINUX_ALSA__)
-
-class RtApiAlsa: public RtApi
-{
-public:
-
-  RtApiAlsa();
-  ~RtApiAlsa();
-  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  void callbackEvent( void );
-
-  private:
-
-  std::vector<RtAudio::DeviceInfo> devices_;
-  void saveDeviceInfo( void );
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__LINUX_PULSE__)
-
-class RtApiPulse: public RtApi
-{
-public:
-  ~RtApiPulse();
-  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  void callbackEvent( void );
-
-  private:
-
-  std::vector<RtAudio::DeviceInfo> devices_;
-  void saveDeviceInfo( void );
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__LINUX_OSS__)
-
-class RtApiOss: public RtApi
-{
-public:
-
-  RtApiOss();
-  ~RtApiOss();
-  RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
-  unsigned int getDeviceCount( void );
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
-  void closeStream( void );
-  void startStream( void );
-  void stopStream( void );
-  void abortStream( void );
-
-  // This function is intended for internal use only.  It must be
-  // public because it is called by the internal callback handler,
-  // which is not a member of RtAudio.  External use of this function
-  // will most likely produce highly undesireable results!
-  void callbackEvent( void );
-
-  private:
-
-  bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
-                        unsigned int firstChannel, unsigned int sampleRate,
-                        RtAudioFormat format, unsigned int *bufferSize,
-                        RtAudio::StreamOptions *options );
-};
-
-#endif
-
-#if defined(__RTAUDIO_DUMMY__)
-
-class RtApiDummy: public RtApi
-{
-public:
-
-  RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); }
-  RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }
-  unsigned int getDeviceCount( void ) { return 0; }
-  RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; }
-  void closeStream( void ) {}
-  void startStream( void ) {}
-  void stopStream( void ) {}
-  void abortStream( void ) {}
-
-  private:
-
-  bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, 
-                        unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
-                        RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
-                        RtAudio::StreamOptions * /*options*/ ) { return false; }
-};
-
-#endif
-
-#endif
-
-// Indentation settings for Vim and Emacs
-//
-// Local Variables:
-// c-basic-offset: 2
-// indent-tabs-mode: nil
-// End:
-//
-// vim: et sts=2 sw=2
diff --git a/src/rtaudio-mod/config/config.guess b/src/rtaudio-mod/config/config.guess
deleted file mode 100644 (file)
index 313be34..0000000
+++ /dev/null
@@ -1,1371 +0,0 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-#   Free Software Foundation, Inc.
-
-timestamp='2004-02-26'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Written by Per Bothner <bothner@cygnus.com>.
-# Please send patches to <config-patches@gnu.org>.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub.  If it succeeds, it prints the system name on stdout, and
-# exits with 0.  Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
-  -h, --help         print this help, then exit
-  -t, --time-stamp   print date of last modification, then exit
-  -v, --version      print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
-  case $1 in
-    --time-stamp | --time* | -t )
-       echo "$timestamp" ; exit 0 ;;
-    --version | -v )
-       echo "$version" ; exit 0 ;;
-    --help | --h* | -h )
-       echo "$usage"; exit 0 ;;
-    -- )     # Stop option processing
-       shift; break ;;
-    - )        # Use stdin as input.
-       break ;;
-    -* )
-       echo "$me: invalid option $1$help" >&2
-       exit 1 ;;
-    * )
-       break ;;
-  esac
-done
-
-if test $# != 0; then
-  echo "$me: too many arguments$help" >&2
-  exit 1
-fi
-
-
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script.
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,)    echo "int dummy(){}" > $dummy.c
-       for c in cc gcc c89 ; do
-         ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1
-         if test $? = 0 ; then
-            CC_FOR_BUILD="$c"; break
-         fi
-       done
-       rm -f $dummy.c $dummy.o $dummy.rel
-       if test x"$CC_FOR_BUILD" = x ; then
-         CC_FOR_BUILD=no_compiler_found
-       fi
-       ;;
- ,,*)   CC_FOR_BUILD=$CC ;;
- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
-       PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
-    *:NetBSD:*:*)
-       # Netbsd (nbsd) targets should (where applicable) match one or
-       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
-       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
-       # switched to ELF, *-*-netbsd* would select the old
-       # object file format.  This provides both forward
-       # compatibility and a consistent mechanism for selecting the
-       # object file format.
-       # Determine the machine/vendor (is the vendor relevant).
-       case "${UNAME_MACHINE}" in
-           amiga) machine=m68k-unknown ;;
-           arm32) machine=arm-unknown ;;
-           atari*) machine=m68k-atari ;;
-           sun3*) machine=m68k-sun ;;
-           mac68k) machine=m68k-apple ;;
-           macppc) machine=powerpc-apple ;;
-           hp3[0-9][05]) machine=m68k-hp ;;
-           ibmrt|romp-ibm) machine=romp-ibm ;;
-           *) machine=${UNAME_MACHINE}-unknown ;;
-       esac
-       # The Operating System including object format, if it has switched
-       # to ELF recently, or will in the future.
-       case "${UNAME_MACHINE}" in
-           i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
-               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
-                       | grep __ELF__ >/dev/null
-               then
-                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
-                   # Return netbsd for either.  FIX?
-                   os=netbsd
-               else
-                   os=netbsdelf
-               fi
-               ;;
-           *)
-               os=netbsd
-               ;;
-       esac
-       # The OS release
-       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
-       # contains redundant information, the shorter form:
-       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "${machine}-${os}${release}"
-       exit 0 ;;
-    alpha:OSF1:*:*)
-       if test $UNAME_RELEASE = "V4.0"; then
-               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
-       fi
-       # A Vn.n version is a released version.
-       # A Tn.n version is a released field test version.
-       # A Xn.n version is an unreleased experimental baselevel.
-       # 1.2 uses "1.2" for uname -r.
-       cat <<EOF >$dummy.s
-       .data
-\$Lformat:
-       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
-
-       .text
-       .globl main
-       .align 4
-       .ent main
-main:
-       .frame \$30,16,\$26,0
-       ldgp \$29,0(\$27)
-       .prologue 1
-       .long 0x47e03d80 # implver \$0
-       lda \$2,-1
-       .long 0x47e20c21 # amask \$2,\$1
-       lda \$16,\$Lformat
-       mov \$0,\$17
-       not \$1,\$18
-       jsr \$26,printf
-       ldgp \$29,0(\$26)
-       mov 0,\$16
-       jsr \$26,exit
-       .end main
-EOF
-       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               case `./$dummy` in
-                       0-0)
-                               UNAME_MACHINE="alpha"
-                               ;;
-                       1-0)
-                               UNAME_MACHINE="alphaev5"
-                               ;;
-                       1-1)
-                               UNAME_MACHINE="alphaev56"
-                               ;;
-                       1-101)
-                               UNAME_MACHINE="alphapca56"
-                               ;;
-                       2-303)
-                               UNAME_MACHINE="alphaev6"
-                               ;;
-                       2-307)
-                               UNAME_MACHINE="alphaev67"
-                               ;;
-               esac
-       fi
-       rm -f $dummy.s $dummy
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-       exit 0 ;;
-    Alpha\ *:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # Should we change UNAME_MACHINE based on the output of uname instead
-       # of the specific Alpha model?
-       echo alpha-pc-interix
-       exit 0 ;;
-    21064:Windows_NT:50:3)
-       echo alpha-dec-winnt3.5
-       exit 0 ;;
-    Amiga*:UNIX_System_V:4.0:*)
-       echo m68k-unknown-sysv4
-       exit 0;;
-    amiga:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    *:[Aa]miga[Oo][Ss]:*:*)
-       echo ${UNAME_MACHINE}-unknown-amigaos
-       exit 0 ;;
-    arc64:OpenBSD:*:*)
-       echo mips64el-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    arc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    hkmips:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    pmax:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    sgi:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    wgrisc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    *:OS/390:*:*)
-       echo i370-ibm-openedition
-       exit 0 ;;
-    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-       echo arm-acorn-riscix${UNAME_RELEASE}
-       exit 0;;
-    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
-       echo hppa1.1-hitachi-hiuxmpp
-       exit 0;;
-    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
-       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-       if test "`(/bin/universe) 2>/dev/null`" = att ; then
-               echo pyramid-pyramid-sysv3
-       else
-               echo pyramid-pyramid-bsd
-       fi
-       exit 0 ;;
-    NILE*:*:*:dcosx)
-       echo pyramid-pyramid-svr4
-       exit 0 ;;
-    sun4H:SunOS:5.*:*)
-       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    i86pc:SunOS:5.*:*)
-       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:6*:*)
-       # According to config.sub, this is the proper way to canonicalize
-       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
-       # it's likely to be more like Solaris than SunOS4.
-       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:*:*)
-       case "`/usr/bin/arch -k`" in
-           Series*|S4*)
-               UNAME_RELEASE=`uname -v`
-               ;;
-       esac
-       # Japanese Language versions have a version number like `4.1.3-JL'.
-       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
-       exit 0 ;;
-    sun3*:SunOS:*:*)
-       echo m68k-sun-sunos${UNAME_RELEASE}
-       exit 0 ;;
-    sun*:*:4.2BSD:*)
-       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
-       case "`/bin/arch`" in
-           sun3)
-               echo m68k-sun-sunos${UNAME_RELEASE}
-               ;;
-           sun4)
-               echo sparc-sun-sunos${UNAME_RELEASE}
-               ;;
-       esac
-       exit 0 ;;
-    aushp:SunOS:*:*)
-       echo sparc-auspex-sunos${UNAME_RELEASE}
-       exit 0 ;;
-    atari*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    # The situation for MiNT is a little confusing.  The machine name
-    # can be virtually everything (everything which is not
-    # "atarist" or "atariste" at least should have a processor
-    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
-    # to the lowercase version "mint" (or "freemint").  Finally
-    # the system name "TOS" denotes a system which is actually not
-    # MiNT.  But MiNT is downward compatible to TOS, so this should
-    # be no problem.
-    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
-       exit 0 ;;
-    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint${UNAME_RELEASE}
-        exit 0 ;;
-    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
-       exit 0 ;;
-    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-        echo m68k-milan-mint${UNAME_RELEASE}
-        exit 0 ;;
-    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-        echo m68k-hades-mint${UNAME_RELEASE}
-        exit 0 ;;
-    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-        echo m68k-unknown-mint${UNAME_RELEASE}
-        exit 0 ;;
-    sun3*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mac68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme88k:OpenBSD:*:*)
-       echo m88k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    powerpc:machten:*:*)
-       echo powerpc-apple-machten${UNAME_RELEASE}
-       exit 0 ;;
-    RISC*:Mach:*:*)
-       echo mips-dec-mach_bsd4.3
-       exit 0 ;;
-    RISC*:ULTRIX:*:*)
-       echo mips-dec-ultrix${UNAME_RELEASE}
-       exit 0 ;;
-    VAX*:ULTRIX*:*:*)
-       echo vax-dec-ultrix${UNAME_RELEASE}
-       exit 0 ;;
-    2020:CLIX:*:* | 2430:CLIX:*:*)
-       echo clipper-intergraph-clix${UNAME_RELEASE}
-       exit 0 ;;
-    mips:*:*:UMIPS | mips:*:*:RISCos)
-       sed 's/^        //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-       #if defined (host_mips) && defined (MIPSEB)
-       #if defined (SYSTYPE_SYSV)
-         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_SVR4)
-         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
-         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
-       #endif
-       #endif
-         exit (-1);
-       }
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy \
-         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
-         && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       echo mips-mips-riscos${UNAME_RELEASE}
-       exit 0 ;;
-    Motorola:PowerMAX_OS:*:*)
-       echo powerpc-motorola-powermax
-       exit 0 ;;
-    Night_Hawk:Power_UNIX:*:*)
-       echo powerpc-harris-powerunix
-       exit 0 ;;
-    m88k:CX/UX:7*:*)
-       echo m88k-harris-cxux7
-       exit 0 ;;
-    m88k:*:4*:R4*)
-       echo m88k-motorola-sysv4
-       exit 0 ;;
-    m88k:*:3*:R3*)
-       echo m88k-motorola-sysv3
-       exit 0 ;;
-    AViiON:dgux:*:*)
-        # DG/UX returns AViiON for all architectures
-        UNAME_PROCESSOR=`/usr/bin/uname -p`
-       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
-       then
-           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
-              [ ${TARGET_BINARY_INTERFACE}x = x ]
-           then
-               echo m88k-dg-dgux${UNAME_RELEASE}
-           else
-               echo m88k-dg-dguxbcs${UNAME_RELEASE}
-           fi
-       else
-           echo i586-dg-dgux${UNAME_RELEASE}
-       fi
-       exit 0 ;;
-    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
-       echo m88k-dolphin-sysv3
-       exit 0 ;;
-    M88*:*:R3*:*)
-       # Delta 88k system running SVR3
-       echo m88k-motorola-sysv3
-       exit 0 ;;
-    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-       echo m88k-tektronix-sysv3
-       exit 0 ;;
-    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-       echo m68k-tektronix-bsd
-       exit 0 ;;
-    *:IRIX*:*:*)
-       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
-       exit 0 ;;
-    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
-       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
-    i*86:AIX:*:*)
-       echo i386-ibm-aix
-       exit 0 ;;
-    ia64:AIX:*:*)
-       if [ -x /usr/bin/oslevel ] ; then
-               IBM_REV=`/usr/bin/oslevel`
-       else
-               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
-       fi
-       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
-       exit 0 ;;
-    *:AIX:2:3)
-       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-               sed 's/^                //' << EOF >$dummy.c
-               #include <sys/systemcfg.h>
-
-               main()
-                       {
-                       if (!__power_pc())
-                               exit(1);
-                       puts("powerpc-ibm-aix3.2.5");
-                       exit(0);
-                       }
-EOF
-               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
-               rm -f $dummy.c $dummy
-               echo rs6000-ibm-aix3.2.5
-       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-               echo rs6000-ibm-aix3.2.4
-       else
-               echo rs6000-ibm-aix3.2
-       fi
-       exit 0 ;;
-    *:AIX:*:[45])
-       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
-       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
-               IBM_ARCH=rs6000
-       else
-               IBM_ARCH=powerpc
-       fi
-       if [ -x /usr/bin/oslevel ] ; then
-               IBM_REV=`/usr/bin/oslevel`
-       else
-               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
-       fi
-       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
-       exit 0 ;;
-    *:AIX:*:*)
-       echo rs6000-ibm-aix
-       exit 0 ;;
-    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
-       echo romp-ibm-bsd4.4
-       exit 0 ;;
-    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
-       exit 0 ;;                           # report: romp-ibm BSD 4.3
-    *:BOSX:*:*)
-       echo rs6000-bull-bosx
-       exit 0 ;;
-    DPX/2?00:B.O.S.:*:*)
-       echo m68k-bull-sysv3
-       exit 0 ;;
-    9000/[34]??:4.3bsd:1.*:*)
-       echo m68k-hp-bsd
-       exit 0 ;;
-    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-       echo m68k-hp-bsd4.4
-       exit 0 ;;
-    9000/[34678]??:HP-UX:*:*)
-       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-       case "${UNAME_MACHINE}" in
-           9000/31? )            HP_ARCH=m68000 ;;
-           9000/[34]?? )         HP_ARCH=m68k ;;
-           9000/[678][0-9][0-9])
-              case "${HPUX_REV}" in
-                11.[0-9][0-9])
-                  if [ -x /usr/bin/getconf ]; then
-                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
-                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-                    case "${sc_cpu_version}" in
-                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
-                      532)                      # CPU_PA_RISC2_0
-                        case "${sc_kernel_bits}" in
-                          32) HP_ARCH="hppa2.0n" ;;
-                          64) HP_ARCH="hppa2.0w" ;;
-                        esac ;;
-                    esac
-                  fi ;;
-              esac
-              if [ "${HP_ARCH}" = "" ]; then
-              sed 's/^              //' << EOF >$dummy.c
-
-              #define _HPUX_SOURCE
-              #include <stdlib.h>
-              #include <unistd.h>
-
-              int main ()
-              {
-              #if defined(_SC_KERNEL_BITS)
-                  long bits = sysconf(_SC_KERNEL_BITS);
-              #endif
-                  long cpu  = sysconf (_SC_CPU_VERSION);
-
-                  switch (cpu)
-               {
-               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
-               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
-               case CPU_PA_RISC2_0:
-              #if defined(_SC_KERNEL_BITS)
-                   switch (bits)
-                       {
-                       case 64: puts ("hppa2.0w"); break;
-                       case 32: puts ("hppa2.0n"); break;
-                       default: puts ("hppa2.0"); break;
-                       } break;
-              #else  /* !defined(_SC_KERNEL_BITS) */
-                   puts ("hppa2.0"); break;
-              #endif
-               default: puts ("hppa1.0"); break;
-               }
-                  exit (0);
-              }
-EOF
-       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
-       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
-       rm -f $dummy.c $dummy
-       fi ;;
-       esac
-       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
-       exit 0 ;;
-    ia64:HP-UX:*:*)
-       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-       echo ia64-hp-hpux${HPUX_REV}
-       exit 0 ;;
-    3050*:HI-UX:*:*)
-       sed 's/^        //' << EOF >$dummy.c
-       #include <unistd.h>
-       int
-       main ()
-       {
-         long cpu = sysconf (_SC_CPU_VERSION);
-         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
-            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
-            results, however.  */
-         if (CPU_IS_PA_RISC (cpu))
-           {
-             switch (cpu)
-               {
-                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
-                 default: puts ("hppa-hitachi-hiuxwe2"); break;
-               }
-           }
-         else if (CPU_IS_HP_MC68K (cpu))
-           puts ("m68k-hitachi-hiuxwe2");
-         else puts ("unknown-hitachi-hiuxwe2");
-         exit (0);
-       }
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       echo unknown-hitachi-hiuxwe2
-       exit 0 ;;
-    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
-       echo hppa1.1-hp-bsd
-       exit 0 ;;
-    9000/8??:4.3bsd:*:*)
-       echo hppa1.0-hp-bsd
-       exit 0 ;;
-    *9??*:MPE/iX:*:*)
-       echo hppa1.0-hp-mpeix
-       exit 0 ;;
-    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
-       echo hppa1.1-hp-osf
-       exit 0 ;;
-    hp8??:OSF1:*:*)
-       echo hppa1.0-hp-osf
-       exit 0 ;;
-    i*86:OSF1:*:*)
-       if [ -x /usr/sbin/sysversion ] ; then
-           echo ${UNAME_MACHINE}-unknown-osf1mk
-       else
-           echo ${UNAME_MACHINE}-unknown-osf1
-       fi
-       exit 0 ;;
-    parisc*:Lites*:*:*)
-       echo hppa1.1-hp-lites
-       exit 0 ;;
-    hppa*:OpenBSD:*:*)
-       echo hppa-unknown-openbsd
-       exit 0 ;;
-    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-       echo c1-convex-bsd
-        exit 0 ;;
-    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-        exit 0 ;;
-    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-       echo c34-convex-bsd
-        exit 0 ;;
-    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-       echo c38-convex-bsd
-        exit 0 ;;
-    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-       echo c4-convex-bsd
-        exit 0 ;;
-    CRAY*X-MP:*:*:*)
-       echo xmp-cray-unicos
-        exit 0 ;;
-    CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos${UNAME_RELEASE}
-       exit 0 ;;
-    CRAY*[A-Z]90:*:*:*)
-       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
-       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
-       exit 0 ;;
-    CRAY*TS:*:*:*)
-       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit 0 ;;
-    CRAY*T3D:*:*:*)
-       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit 0 ;;
-    CRAY*T3E:*:*:*)
-       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit 0 ;;
-    CRAY*SV1:*:*:*)
-       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit 0 ;;
-    CRAY-2:*:*:*)
-       echo cray2-cray-unicos
-        exit 0 ;;
-    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
-        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-        exit 0 ;;
-    hp300:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    *:BSD/OS:*:*)
-       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    *:FreeBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
-       exit 0 ;;
-    *:OpenBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-       exit 0 ;;
-    i*:CYGWIN*:*)
-       echo ${UNAME_MACHINE}-pc-cygwin
-       exit 0 ;;
-    i*:MINGW*:*)
-       echo ${UNAME_MACHINE}-pc-mingw32
-       exit 0 ;;
-    i*:PW*:*)
-       echo ${UNAME_MACHINE}-pc-pw32
-       exit 0 ;;
-    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
-       # UNAME_MACHINE based on the output of uname instead of i386?
-       echo i386-pc-interix
-       exit 0 ;;
-    i*:UWIN*:*)
-       echo ${UNAME_MACHINE}-pc-uwin
-       exit 0 ;;
-    p*:CYGWIN*:*)
-       echo powerpcle-unknown-cygwin
-       exit 0 ;;
-    prep*:SunOS:5.*:*)
-       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    *:GNU:*:*)
-       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
-       exit 0 ;;
-    i*86:Minix:*:*)
-       echo ${UNAME_MACHINE}-pc-minix
-       exit 0 ;;
-    arm*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-gnu
-       exit 0 ;;
-    ia64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux
-       exit 0 ;;
-    m68*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-gnu
-       exit 0 ;;
-    mips:Linux:*:*)
-       cat >$dummy.c <<EOF
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-int main (int argc, char *argv[]) {
-#else
-int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __MIPSEB__
-  printf ("%s-unknown-linux-gnu\n", argv[1]);
-#endif
-#ifdef __MIPSEL__
-  printf ("%sel-unknown-linux-gnu\n", argv[1]);
-#endif
-  return 0;
-}
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       ;;
-    ppc:Linux:*:*)
-       # Determine Lib Version
-       cat >$dummy.c <<EOF
-#include <features.h>
-#if defined(__GLIBC__)
-extern char __libc_version[];
-extern char __libc_release[];
-#endif
-main(argc, argv)
-     int argc;
-     char *argv[];
-{
-#if defined(__GLIBC__)
-  printf("%s %s\n", __libc_version, __libc_release);
-#else
-  printf("unknown\n");
-#endif
-  return 0;
-}
-EOF
-       LIBC=""
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               ./$dummy | grep 1\.99 > /dev/null
-               if test "$?" = 0 ; then LIBC="libc1" ; fi
-       fi
-       rm -f $dummy.c $dummy
-       echo powerpc-unknown-linux-gnu${LIBC}
-       exit 0 ;;
-    alpha:Linux:*:*)
-       cat <<EOF >$dummy.s
-         .data
-         \$Lformat:
-               .byte 37,100,45,37,120,10,0     # "%d-%x\n"
-          .text
-               .globl main
-               .align 4
-               .ent main
-           main:
-               .frame \$30,16,\$26,0
-               ldgp \$29,0(\$27)
-               .prologue 1
-               .long 0x47e03d80 # implver \$0
-               lda \$2,-1
-               .long 0x47e20c21 # amask \$2,\$1
-               lda \$16,\$Lformat
-               mov \$0,\$17
-               not \$1,\$18
-               jsr \$26,printf
-               ldgp \$29,0(\$26)
-               mov 0,\$16
-               jsr \$26,exit
-               .end main
-EOF
-       LIBC=""
-       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               case `./$dummy` in
-               0-0)    UNAME_MACHINE="alpha" ;;
-               1-0)    UNAME_MACHINE="alphaev5" ;;
-               1-1)    UNAME_MACHINE="alphaev56" ;;
-               1-101)  UNAME_MACHINE="alphapca56" ;;
-               2-303)  UNAME_MACHINE="alphaev6" ;;
-               2-307)  UNAME_MACHINE="alphaev67" ;;
-               esac
-               objdump --private-headers $dummy | \
-                 grep ld.so.1 > /dev/null
-               if test "$?" = 0 ; then
-                       LIBC="libc1"
-               fi
-       fi
-       rm -f $dummy.s $dummy
-       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
-       exit 0 ;;
-    parisc:Linux:*:* | hppa:Linux:*:*)
-       # Look for CPU level
-       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-         PA7*) echo hppa1.1-unknown-linux-gnu ;;
-         PA8*) echo hppa2.0-unknown-linux-gnu ;;
-         *)    echo hppa-unknown-linux-gnu ;;
-       esac
-       exit 0 ;;
-    parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-gnu
-       exit 0 ;;
-    s390:Linux:*:* | s390x:Linux:*:*)
-       echo ${UNAME_MACHINE}-ibm-linux
-       exit 0 ;;
-    sh*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-gnu
-       exit 0 ;;
-    sparc:Linux:*:* | sparc64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-gnu
-       exit 0 ;;
-    x86_64:Linux:*:*)
-       echo x86_64-unknown-linux-gnu
-       exit 0 ;;
-    i*86:Linux:*:*)
-       # The BFD linker knows what the default object file format is, so
-       # first see if it will tell us. cd to the root directory to prevent
-       # problems with other programs or directories called `ld' in the path.
-       ld_supported_emulations=`cd /; ld --help 2>&1 \
-                        | sed -ne '/supported emulations:/!d
-                                   s/[         ][      ]*/ /g
-                                   s/.*supported emulations: *//
-                                   s/ .*//
-                                   p'`
-        case "$ld_supported_emulations" in
-         i*86linux)
-               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-               exit 0
-               ;;
-         elf_i*86)
-               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
-               ;;
-         i*86coff)
-               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
-               exit 0
-               ;;
-       esac
-       # Either a pre-BFD a.out linker (linux-gnuoldld)
-       # or one that does not give us useful --help.
-       # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
-       # If ld does not provide *any* "supported emulations:"
-       # that means it is gnuoldld.
-       test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
-       case "${UNAME_MACHINE}" in
-       i*86)
-         VENDOR=pc;
-         ;;
-       *)
-         VENDOR=unknown;
-         ;;
-       esac
-       # Determine whether the default compiler is a.out or elf
-       cat >$dummy.c <<EOF
-#include <features.h>
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __ELF__
-# ifdef __GLIBC__
-#  if __GLIBC__ >= 2
-    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
-#  else
-    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-#  endif
-# else
-   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-#else
-  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
-#endif
-  return 0;
-}
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
-       ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
-# are messed up and put the nodename in both sysname and nodename.
-    i*86:DYNIX/ptx:4*:*)
-       echo i386-sequent-sysv4
-       exit 0 ;;
-    i*86:UNIX_SV:4.2MP:2.*)
-        # Unixware is an offshoot of SVR4, but it has its own version
-        # number series starting with 2...
-        # I am not positive that other SVR4 systems won't match this,
-       # I just have to hope.  -- rms.
-        # Use sysv4.2uw... so that sysv4* matches it.
-       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
-       exit 0 ;;
-    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
-       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
-       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
-       else
-               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
-       fi
-       exit 0 ;;
-    i*86:*:5:7*)
-        # Fixed at (any) Pentium or better
-        UNAME_MACHINE=i586
-        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
-           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
-       else
-           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
-       fi
-       exit 0 ;;
-    i*86:*:3.2:*)
-       if test -f /usr/options/cb.name; then
-               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
-       elif /bin/uname -X 2>/dev/null >/dev/null ; then
-               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
-               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
-               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
-                       && UNAME_MACHINE=i586
-               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
-       else
-               echo ${UNAME_MACHINE}-pc-sysv32
-       fi
-       exit 0 ;;
-    i*86:*DOS:*:*)
-       echo ${UNAME_MACHINE}-pc-msdosdjgpp
-       exit 0 ;;
-    pc:*:*:*)
-       # Left here for compatibility:
-        # uname -m prints for DJGPP always 'pc', but it prints nothing about
-        # the processor, so we play safe by assuming i386.
-       echo i386-pc-msdosdjgpp
-        exit 0 ;;
-    Intel:Mach:3*:*)
-       echo i386-pc-mach3
-       exit 0 ;;
-    paragon:*:*:*)
-       echo i860-intel-osf1
-       exit 0 ;;
-    i860:*:4.*:*) # i860-SVR4
-       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
-       else # Add other i860-SVR4 vendors below as they are discovered.
-         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
-       fi
-       exit 0 ;;
-    mini*:CTIX:SYS*5:*)
-       # "miniframe"
-       echo m68010-convergent-sysv
-       exit 0 ;;
-    M68*:*:R3V[567]*:*)
-       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
-    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
-       OS_REL=''
-       test -r /etc/.relid \
-       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
-       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
-       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
-    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
-        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-          && echo i486-ncr-sysv4 && exit 0 ;;
-    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-       echo m68k-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    mc68030:UNIX_System_V:4.*:*)
-       echo m68k-atari-sysv4
-       exit 0 ;;
-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
-       echo i386-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    TSUNAMI:LynxOS:2.*:*)
-       echo sparc-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    rs6000:LynxOS:2.*:*)
-       echo rs6000-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
-       echo powerpc-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    SM[BE]S:UNIX_SV:*:*)
-       echo mips-dde-sysv${UNAME_RELEASE}
-       exit 0 ;;
-    RM*:ReliantUNIX-*:*:*)
-       echo mips-sni-sysv4
-       exit 0 ;;
-    RM*:SINIX-*:*:*)
-       echo mips-sni-sysv4
-       exit 0 ;;
-    *:SINIX-*:*:*)
-       if uname -p 2>/dev/null >/dev/null ; then
-               UNAME_MACHINE=`(uname -p) 2>/dev/null`
-               echo ${UNAME_MACHINE}-sni-sysv4
-       else
-               echo ns32k-sni-sysv
-       fi
-       exit 0 ;;
-    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                           # says <Richard.M.Bartel@ccMail.Census.GOV>
-        echo i586-unisys-sysv4
-        exit 0 ;;
-    *:UNIX_System_V:4*:FTX*)
-       # From Gerald Hewes <hewes@openmarket.com>.
-       # How about differentiating between stratus architectures? -djm
-       echo hppa1.1-stratus-sysv4
-       exit 0 ;;
-    *:*:*:FTX*)
-       # From seanf@swdc.stratus.com.
-       echo i860-stratus-sysv4
-       exit 0 ;;
-    mc68*:A/UX:*:*)
-       echo m68k-apple-aux${UNAME_RELEASE}
-       exit 0 ;;
-    news*:NEWS-OS:6*:*)
-       echo mips-sony-newsos6
-       exit 0 ;;
-    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-       if [ -d /usr/nec ]; then
-               echo mips-nec-sysv${UNAME_RELEASE}
-       else
-               echo mips-unknown-sysv${UNAME_RELEASE}
-       fi
-        exit 0 ;;
-    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
-       echo powerpc-be-beos
-       exit 0 ;;
-    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
-       echo powerpc-apple-beos
-       exit 0 ;;
-    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
-       echo i586-pc-beos
-       exit 0 ;;
-    SX-4:SUPER-UX:*:*)
-       echo sx4-nec-superux${UNAME_RELEASE}
-       exit 0 ;;
-    SX-5:SUPER-UX:*:*)
-       echo sx5-nec-superux${UNAME_RELEASE}
-       exit 0 ;;
-    Power*:Rhapsody:*:*)
-       echo powerpc-apple-rhapsody${UNAME_RELEASE}
-       exit 0 ;;
-    *:Rhapsody:*:*)
-       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
-       exit 0 ;;
-    *:Darwin:*:*)
-       echo `uname -p`-apple-darwin${UNAME_RELEASE}
-       exit 0 ;;
-    *:procnto*:*:* | *:QNX:[0123456789]*:*)
-       if test "${UNAME_MACHINE}" = "x86pc"; then
-               UNAME_MACHINE=pc
-       fi
-       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
-       exit 0 ;;
-    *:QNX:*:4*)
-       echo i386-pc-qnx
-       exit 0 ;;
-    NSR-[KW]:NONSTOP_KERNEL:*:*)
-       echo nsr-tandem-nsk${UNAME_RELEASE}
-       exit 0 ;;
-    *:NonStop-UX:*:*)
-       echo mips-compaq-nonstopux
-       exit 0 ;;
-    BS2000:POSIX*:*:*)
-       echo bs2000-siemens-sysv
-       exit 0 ;;
-    DS/*:UNIX_System_V:*:*)
-       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
-       exit 0 ;;
-    *:Plan9:*:*)
-       # "uname -m" is not consistent, so use $cputype instead. 386
-       # is converted to i386 for consistency with other x86
-       # operating systems.
-       if test "$cputype" = "386"; then
-           UNAME_MACHINE=i386
-       else
-           UNAME_MACHINE="$cputype"
-       fi
-       echo ${UNAME_MACHINE}-unknown-plan9
-       exit 0 ;;
-    i*86:OS/2:*:*)
-       # If we were able to find `uname', then EMX Unix compatibility
-       # is probably installed.
-       echo ${UNAME_MACHINE}-pc-os2-emx
-       exit 0 ;;
-    *:TOPS-10:*:*)
-       echo pdp10-unknown-tops10
-       exit 0 ;;
-    *:TENEX:*:*)
-       echo pdp10-unknown-tenex
-       exit 0 ;;
-    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
-       echo pdp10-dec-tops20
-       exit 0 ;;
-    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
-       echo pdp10-xkl-tops20
-       exit 0 ;;
-    *:TOPS-20:*:*)
-       echo pdp10-unknown-tops20
-       exit 0 ;;
-    *:ITS:*:*)
-       echo pdp10-unknown-its
-       exit 0 ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-          "4"
-#else
-         ""
-#endif
-         ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-       printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-       printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-       echo c1-convex-bsd
-       exit 0 ;;
-    c2*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-       exit 0 ;;
-    c34*)
-       echo c34-convex-bsd
-       exit 0 ;;
-    c38*)
-       echo c38-convex-bsd
-       exit 0 ;;
-    c4*)
-       echo c4-convex-bsd
-       exit 0 ;;
-    esac
-fi
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
-
-    ftp://ftp.gnu.org/pub/gnu/config/
-
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo               = `(hostinfo) 2>/dev/null`
-/bin/universe          = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch              = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM  = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/src/rtaudio-mod/config/config.sub b/src/rtaudio-mod/config/config.sub
deleted file mode 100755 (executable)
index 9a7d59a..0000000
+++ /dev/null
@@ -1,1366 +0,0 @@
-#! /bin/sh
-# Configuration validation subroutine script.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-#   Free Software Foundation, Inc.
-
-timestamp='2012-11-19'
-
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine.  It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Please send patches to <config-patches@gnu.org>.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support.  The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
-  -h, --help         print this help, then exit
-  -t, --time-stamp   print date of last modification, then exit
-  -v, --version      print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
-  case $1 in
-    --time-stamp | --time* | -t )
-       echo "$timestamp" ; exit 0 ;;
-    --version | -v )
-       echo "$version" ; exit 0 ;;
-    --help | --h* | -h )
-       echo "$usage"; exit 0 ;;
-    -- )     # Stop option processing
-       shift; break ;;
-    - )        # Use stdin as input.
-       break ;;
-    -* )
-       echo "$me: invalid option $1$help"
-       exit 1 ;;
-
-    *local*)
-       # First pass through any local machine types.
-       echo $1
-       exit 0;;
-
-    * )
-       break ;;
-  esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
-    exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
-    exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
-  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
-    os=-$maybe_os
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
-    ;;
-  *)
-    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
-    if [ $basic_machine != $1 ]
-    then os=`echo $1 | sed 's/.*-/-/'`
-    else os=; fi
-    ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work.  We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
-       -sun*os*)
-               # Prevent following clause from handling this invalid input.
-               ;;
-       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple | -axis)
-               os=
-               basic_machine=$1
-               ;;
-       -sim | -cisco | -oki | -wec | -winbond)
-               os=
-               basic_machine=$1
-               ;;
-       -scout)
-               ;;
-       -wrs)
-               os=-vxworks
-               basic_machine=$1
-               ;;
-       -hiux*)
-               os=-hiuxwe2
-               ;;
-       -sco5)
-               os=-sco3.2v5
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco4)
-               os=-sco3.2v4
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2.[4-9]*)
-               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2v[4-9]*)
-               # Don't forget version if it is 3.2v4 or newer.
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco*)
-               os=-sco3.2v2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -udk*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -isc)
-               os=-isc2.2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -clix*)
-               basic_machine=clipper-intergraph
-               ;;
-       -isc*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -lynx*)
-               os=-lynxos
-               ;;
-       -ptx*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
-               ;;
-       -windowsnt*)
-               os=`echo $os | sed -e 's/windowsnt/winnt/'`
-               ;;
-       -psos*)
-               os=-psos
-               ;;
-       -mint | -mint[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
-       # Recognize the basic CPU types without company name.
-       # Some are omitted here because they have special meanings below.
-       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
-               | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
-               | pyramid | mn10200 | mn10300 | tron | a29k \
-               | 580 | i960 | h8300 \
-               | x86 | ppcbe | mipsbe | mipsle | shbe | shle \
-               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
-               | hppa64 \
-               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
-               | alphaev6[78] \
-               | we32k | ns16k | clipper | i370 | sh | sh[34] \
-               | powerpc | powerpc64 | powerpcle \
-               | 1750a | dsp16xx | pdp10 | pdp11 \
-               | mips16 | mips64 | mipsel | mips64el \
-               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
-               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
-               | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
-               | sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \
-               | v850 | c4x \
-               | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
-               | pj | pjl | h8500)
-               basic_machine=$basic_machine-unknown
-               ;;
-       m6811 | m68hc11 | m6812 | m68hc12)
-               # Motorola 68HC11/12.
-               basic_machine=$basic_machine-unknown
-               os=-none
-               ;;
-       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65)
-               ;;
-
-       # We use `pc' rather than `unknown'
-       # because (1) that's what they normally are, and
-       # (2) the word "unknown" tends to confuse beginning users.
-       i*86 | x86_64)
-         basic_machine=$basic_machine-pc
-         ;;
-       # Object if more than one company name word.
-       *-*-*)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-       # Recognize the basic CPU types with company name.
-       # FIXME: clean up the formatting here.
-       vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
-             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
-             | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
-             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
-             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
-             | xmp-* | ymp-* \
-             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
-             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
-             | hppa2.0n-* | hppa64-* \
-             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
-             | alphaev6[78]-* \
-             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
-             | clipper-* | orion-* \
-             | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpc64-* | powerpcle-* \
-             | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \
-             | mips16-* | mips64-* | mipsel-* \
-             | mips64el-* | mips64orion-* | mips64orionel-* \
-             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
-             | mipstx39-* | mipstx39el-* | mcore-* \
-             | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
-             | [cjt]90-* \
-             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
-             | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
-             | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
-               ;;
-       # Recognize the various machine names and aliases which stand
-       # for a CPU type and a company and sometimes even an OS.
-       386bsd)
-               basic_machine=i386-unknown
-               os=-bsd
-               ;;
-       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-               basic_machine=m68000-att
-               ;;
-       3b*)
-               basic_machine=we32k-att
-               ;;
-       a29khif)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       adobe68k)
-               basic_machine=m68010-adobe
-               os=-scout
-               ;;
-       alliant | fx80)
-               basic_machine=fx80-alliant
-               ;;
-       altos | altos3068)
-               basic_machine=m68k-altos
-               ;;
-       am29k)
-               basic_machine=a29k-none
-               os=-bsd
-               ;;
-       amdahl)
-               basic_machine=580-amdahl
-               os=-sysv
-               ;;
-       amiga | amiga-*)
-               basic_machine=m68k-unknown
-               ;;
-       amigaos | amigados)
-               basic_machine=m68k-unknown
-               os=-amigaos
-               ;;
-       amigaunix | amix)
-               basic_machine=m68k-unknown
-               os=-sysv4
-               ;;
-       apollo68)
-               basic_machine=m68k-apollo
-               os=-sysv
-               ;;
-       apollo68bsd)
-               basic_machine=m68k-apollo
-               os=-bsd
-               ;;
-       aux)
-               basic_machine=m68k-apple
-               os=-aux
-               ;;
-       balance)
-               basic_machine=ns32k-sequent
-               os=-dynix
-               ;;
-       convex-c1)
-               basic_machine=c1-convex
-               os=-bsd
-               ;;
-       convex-c2)
-               basic_machine=c2-convex
-               os=-bsd
-               ;;
-       convex-c32)
-               basic_machine=c32-convex
-               os=-bsd
-               ;;
-       convex-c34)
-               basic_machine=c34-convex
-               os=-bsd
-               ;;
-       convex-c38)
-               basic_machine=c38-convex
-               os=-bsd
-               ;;
-       cray | ymp)
-               basic_machine=ymp-cray
-               os=-unicos
-               ;;
-       cray2)
-               basic_machine=cray2-cray
-               os=-unicos
-               ;;
-       [cjt]90)
-               basic_machine=${basic_machine}-cray
-               os=-unicos
-               ;;
-       crds | unos)
-               basic_machine=m68k-crds
-               ;;
-       cris | cris-* | etrax*)
-               basic_machine=cris-axis
-               ;;
-       da30 | da30-*)
-               basic_machine=m68k-da30
-               ;;
-       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-               basic_machine=mips-dec
-               ;;
-       delta | 3300 | motorola-3300 | motorola-delta \
-             | 3300-motorola | delta-motorola)
-               basic_machine=m68k-motorola
-               ;;
-       delta88)
-               basic_machine=m88k-motorola
-               os=-sysv3
-               ;;
-       dpx20 | dpx20-*)
-               basic_machine=rs6000-bull
-               os=-bosx
-               ;;
-       dpx2* | dpx2*-bull)
-               basic_machine=m68k-bull
-               os=-sysv3
-               ;;
-       ebmon29k)
-               basic_machine=a29k-amd
-               os=-ebmon
-               ;;
-       elxsi)
-               basic_machine=elxsi-elxsi
-               os=-bsd
-               ;;
-       encore | umax | mmax)
-               basic_machine=ns32k-encore
-               ;;
-       es1800 | OSE68k | ose68k | ose | OSE)
-               basic_machine=m68k-ericsson
-               os=-ose
-               ;;
-       fx2800)
-               basic_machine=i860-alliant
-               ;;
-       genix)
-               basic_machine=ns32k-ns
-               ;;
-       gmicro)
-               basic_machine=tron-gmicro
-               os=-sysv
-               ;;
-       go32)
-               basic_machine=i386-pc
-               os=-go32
-               ;;
-       h3050r* | hiux*)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       h8300hms)
-               basic_machine=h8300-hitachi
-               os=-hms
-               ;;
-       h8300xray)
-               basic_machine=h8300-hitachi
-               os=-xray
-               ;;
-       h8500hms)
-               basic_machine=h8500-hitachi
-               os=-hms
-               ;;
-       harris)
-               basic_machine=m88k-harris
-               os=-sysv3
-               ;;
-       hp300-*)
-               basic_machine=m68k-hp
-               ;;
-       hp300bsd)
-               basic_machine=m68k-hp
-               os=-bsd
-               ;;
-       hp300hpux)
-               basic_machine=m68k-hp
-               os=-hpux
-               ;;
-       hp3k9[0-9][0-9] | hp9[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k2[0-9][0-9] | hp9k31[0-9])
-               basic_machine=m68000-hp
-               ;;
-       hp9k3[2-9][0-9])
-               basic_machine=m68k-hp
-               ;;
-       hp9k6[0-9][0-9] | hp6[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k7[0-79][0-9] | hp7[0-79][0-9])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k78[0-9] | hp78[0-9])
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][13679] | hp8[0-9][13679])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][0-9] | hp8[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hppa-next)
-               os=-nextstep3
-               ;;
-       hppaosf)
-               basic_machine=hppa1.1-hp
-               os=-osf
-               ;;
-       hppro)
-               basic_machine=hppa1.1-hp
-               os=-proelf
-               ;;
-       i370-ibm* | ibm*)
-               basic_machine=i370-ibm
-               ;;
-# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
-       i*86v32)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv32
-               ;;
-       i*86v4*)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv4
-               ;;
-       i*86v)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv
-               ;;
-       i*86sol2)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-solaris2
-               ;;
-       i386mach)
-               basic_machine=i386-mach
-               os=-mach
-               ;;
-       i386-vsta | vsta)
-               basic_machine=i386-unknown
-               os=-vsta
-               ;;
-       iris | iris4d)
-               basic_machine=mips-sgi
-               case $os in
-                   -irix*)
-                       ;;
-                   *)
-                       os=-irix4
-                       ;;
-               esac
-               ;;
-       isi68 | isi)
-               basic_machine=m68k-isi
-               os=-sysv
-               ;;
-       m88k-omron*)
-               basic_machine=m88k-omron
-               ;;
-       magnum | m3230)
-               basic_machine=mips-mips
-               os=-sysv
-               ;;
-       merlin)
-               basic_machine=ns32k-utek
-               os=-sysv
-               ;;
-       mingw32)
-               basic_machine=i386-pc
-               os=-mingw32
-               ;;
-       miniframe)
-               basic_machine=m68000-convergent
-               ;;
-       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-       mipsel*-linux*)
-               basic_machine=mipsel-unknown
-               os=-linux-gnu
-               ;;
-       mips*-linux*)
-               basic_machine=mips-unknown
-               os=-linux-gnu
-               ;;
-       mips3*-*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
-               ;;
-       mips3*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
-               ;;
-       mmix*)
-               basic_machine=mmix-knuth
-               os=-mmixware
-               ;;
-       monitor)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       msdos)
-               basic_machine=i386-pc
-               os=-msdos
-               ;;
-       mvs)
-               basic_machine=i370-ibm
-               os=-mvs
-               ;;
-       ncr3000)
-               basic_machine=i486-ncr
-               os=-sysv4
-               ;;
-       netbsd386)
-               basic_machine=i386-unknown
-               os=-netbsd
-               ;;
-       netwinder)
-               basic_machine=armv4l-rebel
-               os=-linux
-               ;;
-       news | news700 | news800 | news900)
-               basic_machine=m68k-sony
-               os=-newsos
-               ;;
-       news1000)
-               basic_machine=m68030-sony
-               os=-newsos
-               ;;
-       news-3600 | risc-news)
-               basic_machine=mips-sony
-               os=-newsos
-               ;;
-       necv70)
-               basic_machine=v70-nec
-               os=-sysv
-               ;;
-       next | m*-next )
-               basic_machine=m68k-next
-               case $os in
-                   -nextstep* )
-                       ;;
-                   -ns2*)
-                     os=-nextstep2
-                       ;;
-                   *)
-                     os=-nextstep3
-                       ;;
-               esac
-               ;;
-       nh3000)
-               basic_machine=m68k-harris
-               os=-cxux
-               ;;
-       nh[45]000)
-               basic_machine=m88k-harris
-               os=-cxux
-               ;;
-       nindy960)
-               basic_machine=i960-intel
-               os=-nindy
-               ;;
-       mon960)
-               basic_machine=i960-intel
-               os=-mon960
-               ;;
-       nonstopux)
-               basic_machine=mips-compaq
-               os=-nonstopux
-               ;;
-       np1)
-               basic_machine=np1-gould
-               ;;
-       nsr-tandem)
-               basic_machine=nsr-tandem
-               ;;
-       op50n-* | op60c-*)
-               basic_machine=hppa1.1-oki
-               os=-proelf
-               ;;
-       OSE68000 | ose68000)
-               basic_machine=m68000-ericsson
-               os=-ose
-               ;;
-       os68k)
-               basic_machine=m68k-none
-               os=-os68k
-               ;;
-       pa-hitachi)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       paragon)
-               basic_machine=i860-intel
-               os=-osf
-               ;;
-       pbd)
-               basic_machine=sparc-tti
-               ;;
-       pbb)
-               basic_machine=m68k-tti
-               ;;
-        pc532 | pc532-*)
-               basic_machine=ns32k-pc532
-               ;;
-       pentium | p5 | k5 | k6 | nexgen)
-               basic_machine=i586-pc
-               ;;
-       pentiumpro | p6 | 6x86 | athlon)
-               basic_machine=i686-pc
-               ;;
-       pentiumii | pentium2)
-               basic_machine=i686-pc
-               ;;
-       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
-               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumpro-* | p6-* | 6x86-* | athlon-*)
-               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumii-* | pentium2-*)
-               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pn)
-               basic_machine=pn-gould
-               ;;
-       power)  basic_machine=power-ibm
-               ;;
-       ppc)    basic_machine=powerpc-unknown
-               ;;
-       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppc64)  basic_machine=powerpc64-unknown
-               ;;
-       ppc64-*)        basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppcle | powerpclittle | ppc-le | powerpc-little)
-               basic_machine=powerpcle-unknown
-               ;;
-       ppcle-* | powerpclittle-*)
-               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ps2)
-               basic_machine=i386-ibm
-               ;;
-       pw32)
-               basic_machine=i586-unknown
-               os=-pw32
-               ;;
-       rom68k)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       rm[46]00)
-               basic_machine=mips-siemens
-               ;;
-       rtpc | rtpc-*)
-               basic_machine=romp-ibm
-               ;;
-       sa29200)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       sequent)
-               basic_machine=i386-sequent
-               ;;
-       sh)
-               basic_machine=sh-hitachi
-               os=-hms
-               ;;
-       sparclite-wrs)
-               basic_machine=sparclite-wrs
-               os=-vxworks
-               ;;
-       sps7)
-               basic_machine=m68k-bull
-               os=-sysv2
-               ;;
-       spur)
-               basic_machine=spur-unknown
-               ;;
-       st2000)
-               basic_machine=m68k-tandem
-               ;;
-       stratus)
-               basic_machine=i860-stratus
-               os=-sysv4
-               ;;
-       sun2)
-               basic_machine=m68000-sun
-               ;;
-       sun2os3)
-               basic_machine=m68000-sun
-               os=-sunos3
-               ;;
-       sun2os4)
-               basic_machine=m68000-sun
-               os=-sunos4
-               ;;
-       sun3os3)
-               basic_machine=m68k-sun
-               os=-sunos3
-               ;;
-       sun3os4)
-               basic_machine=m68k-sun
-               os=-sunos4
-               ;;
-       sun4os3)
-               basic_machine=sparc-sun
-               os=-sunos3
-               ;;
-       sun4os4)
-               basic_machine=sparc-sun
-               os=-sunos4
-               ;;
-       sun4sol2)
-               basic_machine=sparc-sun
-               os=-solaris2
-               ;;
-       sun3 | sun3-*)
-               basic_machine=m68k-sun
-               ;;
-       sun4)
-               basic_machine=sparc-sun
-               ;;
-       sun386 | sun386i | roadrunner)
-               basic_machine=i386-sun
-               ;;
-       sv1)
-               basic_machine=sv1-cray
-               os=-unicos
-               ;;
-       symmetry)
-               basic_machine=i386-sequent
-               os=-dynix
-               ;;
-       t3e)
-               basic_machine=t3e-cray
-               os=-unicos
-               ;;
-       tic54x | c54x*)
-               basic_machine=tic54x-unknown
-               os=-coff
-               ;;
-       tx39)
-               basic_machine=mipstx39-unknown
-               ;;
-       tx39el)
-               basic_machine=mipstx39el-unknown
-               ;;
-       tower | tower-32)
-               basic_machine=m68k-ncr
-               ;;
-       udi29k)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       ultra3)
-               basic_machine=a29k-nyu
-               os=-sym1
-               ;;
-       v810 | necv810)
-               basic_machine=v810-nec
-               os=-none
-               ;;
-       vaxv)
-               basic_machine=vax-dec
-               os=-sysv
-               ;;
-       vms)
-               basic_machine=vax-dec
-               os=-vms
-               ;;
-       vpp*|vx|vx-*)
-               basic_machine=f301-fujitsu
-               ;;
-       vxworks960)
-               basic_machine=i960-wrs
-               os=-vxworks
-               ;;
-       vxworks68)
-               basic_machine=m68k-wrs
-               os=-vxworks
-               ;;
-       vxworks29k)
-               basic_machine=a29k-wrs
-               os=-vxworks
-               ;;
-       w65*)
-               basic_machine=w65-wdc
-               os=-none
-               ;;
-       w89k-*)
-               basic_machine=hppa1.1-winbond
-               os=-proelf
-               ;;
-       xmp)
-               basic_machine=xmp-cray
-               os=-unicos
-               ;;
-        xps | xps100)
-               basic_machine=xps100-honeywell
-               ;;
-       z8k-*-coff)
-               basic_machine=z8k-unknown
-               os=-sim
-               ;;
-       none)
-               basic_machine=none-none
-               os=-none
-               ;;
-
-# Here we handle the default manufacturer of certain CPU types.  It is in
-# some cases the only manufacturer, in others, it is the most popular.
-       w89k)
-               basic_machine=hppa1.1-winbond
-               ;;
-       op50n)
-               basic_machine=hppa1.1-oki
-               ;;
-       op60c)
-               basic_machine=hppa1.1-oki
-               ;;
-       mips)
-               if [ x$os = x-linux-gnu ]; then
-                       basic_machine=mips-unknown
-               else
-                       basic_machine=mips-mips
-               fi
-               ;;
-       romp)
-               basic_machine=romp-ibm
-               ;;
-       rs6000)
-               basic_machine=rs6000-ibm
-               ;;
-       vax)
-               basic_machine=vax-dec
-               ;;
-       pdp10)
-               # there are many clones, so DEC is not a safe bet
-               basic_machine=pdp10-unknown
-               ;;
-       pdp11)
-               basic_machine=pdp11-dec
-               ;;
-       we32k)
-               basic_machine=we32k-att
-               ;;
-       sh3 | sh4)
-               basic_machine=sh-unknown
-               ;;
-       sparc | sparcv9 | sparcv9b)
-               basic_machine=sparc-sun
-               ;;
-        cydra)
-               basic_machine=cydra-cydrome
-               ;;
-       orion)
-               basic_machine=orion-highlevel
-               ;;
-       orion105)
-               basic_machine=clipper-highlevel
-               ;;
-       mac | mpw | mac-mpw)
-               basic_machine=m68k-apple
-               ;;
-       pmac | pmac-mpw)
-               basic_machine=powerpc-apple
-               ;;
-       c4x*)
-               basic_machine=c4x-none
-               os=-coff
-               ;;
-       *-unknown)
-               # Make sure to match an already-canonicalized machine name.
-               ;;
-       *)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
-       *-digital*)
-               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
-               ;;
-       *-commodore*)
-               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
-               ;;
-       *)
-               ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
-        # First match some system type aliases
-        # that might get confused with valid system types.
-       # -solaris* is a basic system type, with this one exception.
-       -solaris1 | -solaris1.*)
-               os=`echo $os | sed -e 's|solaris1|sunos4|'`
-               ;;
-       -solaris)
-               os=-solaris2
-               ;;
-       -svr4*)
-               os=-sysv4
-               ;;
-       -unixware*)
-               os=-sysv4.2uw
-               ;;
-       -gnu/linux*)
-               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
-               ;;
-       # First accept the basic system types.
-       # The portable systems comes first.
-       # Each alternative MUST END IN A *, to match a version number.
-       # -sysv* is not here because it comes later, after sysvr4.
-       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
-             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
-             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* \
-             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
-             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
-             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
-             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
-             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
-             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
-             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
-       # Remember, each alternative MUST END IN *, to match a version number.
-               ;;
-       -qnx*)
-               case $basic_machine in
-                   x86-* | i*86-*)
-                       ;;
-                   *)
-                       os=-nto$os
-                       ;;
-               esac
-               ;;
-       -nto*)
-               os=-nto-qnx
-               ;;
-       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
-             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
-             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
-               ;;
-       -mac*)
-               os=`echo $os | sed -e 's|mac|macos|'`
-               ;;
-       -linux*)
-               os=`echo $os | sed -e 's|linux|linux-gnu|'`
-               ;;
-       -sunos5*)
-               os=`echo $os | sed -e 's|sunos5|solaris2|'`
-               ;;
-       -sunos6*)
-               os=`echo $os | sed -e 's|sunos6|solaris3|'`
-               ;;
-       -opened*)
-               os=-openedition
-               ;;
-       -wince*)
-               os=-wince
-               ;;
-       -osfrose*)
-               os=-osfrose
-               ;;
-       -osf*)
-               os=-osf
-               ;;
-       -utek*)
-               os=-bsd
-               ;;
-       -dynix*)
-               os=-bsd
-               ;;
-       -acis*)
-               os=-aos
-               ;;
-       -386bsd)
-               os=-bsd
-               ;;
-       -ctix* | -uts*)
-               os=-sysv
-               ;;
-       -ns2 )
-               os=-nextstep2
-               ;;
-       -nsk*)
-               os=-nsk
-               ;;
-       # Preserve the version number of sinix5.
-       -sinix5.*)
-               os=`echo $os | sed -e 's|sinix|sysv|'`
-               ;;
-       -sinix*)
-               os=-sysv4
-               ;;
-       -triton*)
-               os=-sysv3
-               ;;
-       -oss*)
-               os=-sysv3
-               ;;
-       -svr4)
-               os=-sysv4
-               ;;
-       -svr3)
-               os=-sysv3
-               ;;
-       -sysvr4)
-               os=-sysv4
-               ;;
-       # This must come after -sysvr4.
-       -sysv*)
-               ;;
-       -ose*)
-               os=-ose
-               ;;
-       -es1800*)
-               os=-ose
-               ;;
-       -xenix)
-               os=-xenix
-               ;;
-        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-               os=-mint
-               ;;
-       -none)
-               ;;
-       *)
-               # Get rid of the `-' at the beginning of $os.
-               os=`echo $os | sed 's/[^-]*-//'`
-               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system.  Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
-       *-acorn)
-               os=-riscix1.2
-               ;;
-       arm*-rebel)
-               os=-linux
-               ;;
-       arm*-semi)
-               os=-aout
-               ;;
-       pdp10-*)
-               os=-tops20
-               ;;
-        pdp11-*)
-               os=-none
-               ;;
-       *-dec | vax-*)
-               os=-ultrix4.2
-               ;;
-       m68*-apollo)
-               os=-domain
-               ;;
-       i386-sun)
-               os=-sunos4.0.2
-               ;;
-       m68000-sun)
-               os=-sunos3
-               # This also exists in the configure program, but was not the
-               # default.
-               # os=-sunos4
-               ;;
-       m68*-cisco)
-               os=-aout
-               ;;
-       mips*-cisco)
-               os=-elf
-               ;;
-       mips*-*)
-               os=-elf
-               ;;
-       *-tti)  # must be before sparc entry or we get the wrong os.
-               os=-sysv3
-               ;;
-       sparc-* | *-sun)
-               os=-sunos4.1.1
-               ;;
-       *-be)
-               os=-beos
-               ;;
-       *-ibm)
-               os=-aix
-               ;;
-       *-wec)
-               os=-proelf
-               ;;
-       *-winbond)
-               os=-proelf
-               ;;
-       *-oki)
-               os=-proelf
-               ;;
-       *-hp)
-               os=-hpux
-               ;;
-       *-hitachi)
-               os=-hiux
-               ;;
-       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
-               os=-sysv
-               ;;
-       *-cbm)
-               os=-amigaos
-               ;;
-       *-dg)
-               os=-dgux
-               ;;
-       *-dolphin)
-               os=-sysv3
-               ;;
-       m68k-ccur)
-               os=-rtu
-               ;;
-       m88k-omron*)
-               os=-luna
-               ;;
-       *-next )
-               os=-nextstep
-               ;;
-       *-sequent)
-               os=-ptx
-               ;;
-       *-crds)
-               os=-unos
-               ;;
-       *-ns)
-               os=-genix
-               ;;
-       i370-*)
-               os=-mvs
-               ;;
-       *-next)
-               os=-nextstep3
-               ;;
-        *-gould)
-               os=-sysv
-               ;;
-        *-highlevel)
-               os=-bsd
-               ;;
-       *-encore)
-               os=-bsd
-               ;;
-        *-sgi)
-               os=-irix
-               ;;
-        *-siemens)
-               os=-sysv4
-               ;;
-       *-masscomp)
-               os=-rtu
-               ;;
-       f30[01]-fujitsu | f700-fujitsu)
-               os=-uxpv
-               ;;
-       *-rom68k)
-               os=-coff
-               ;;
-       *-*bug)
-               os=-coff
-               ;;
-       *-apple)
-               os=-macos
-               ;;
-       *-atari*)
-               os=-mint
-               ;;
-       *)
-               os=-none
-               ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer.  We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
-       *-unknown)
-               case $os in
-                       -riscix*)
-                               vendor=acorn
-                               ;;
-                       -sunos*)
-                               vendor=sun
-                               ;;
-                       -aix*)
-                               vendor=ibm
-                               ;;
-                       -beos*)
-                               vendor=be
-                               ;;
-                       -hpux*)
-                               vendor=hp
-                               ;;
-                       -mpeix*)
-                               vendor=hp
-                               ;;
-                       -hiux*)
-                               vendor=hitachi
-                               ;;
-                       -unos*)
-                               vendor=crds
-                               ;;
-                       -dgux*)
-                               vendor=dg
-                               ;;
-                       -luna*)
-                               vendor=omron
-                               ;;
-                       -genix*)
-                               vendor=ns
-                               ;;
-                       -mvs* | -opened*)
-                               vendor=ibm
-                               ;;
-                       -ptx*)
-                               vendor=sequent
-                               ;;
-                       -vxsim* | -vxworks*)
-                               vendor=wrs
-                               ;;
-                       -aux*)
-                               vendor=apple
-                               ;;
-                       -hms*)
-                               vendor=hitachi
-                               ;;
-                       -mpw* | -macos*)
-                               vendor=apple
-                               ;;
-                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-                               vendor=atari
-                               ;;
-               esac
-               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
-               ;;
-esac
-
-echo $basic_machine$os
-exit 0
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/src/rtaudio-mod/config/install.sh b/src/rtaudio-mod/config/install.sh
deleted file mode 100755 (executable)
index e69de29..0000000
diff --git a/src/rtaudio-mod/configure b/src/rtaudio-mod/configure
deleted file mode 100755 (executable)
index 9f3d3f8..0000000
+++ /dev/null
@@ -1,5888 +0,0 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for RtAudio 4.1.
-#
-# Report bugs to <gary@music.mcgill.ca>.
-#
-#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-       expr "X$arg" : "X\\(.*\\)$as_nl";
-       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""       $as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-# Use a proper internal environment variable to ensure we don't fall
-  # into an infinite loop, continuously re-executing ourselves.
-  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
-    _as_can_reexec=no; export _as_can_reexec;
-    # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
-  fi
-  # We don't want this to propagate to other subprocesses.
-          { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
-  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '\${1+\"\$@\"}'='\"\$@\"'
-  setopt NO_GLOB_SUBST
-else
-  case \`(set -o) 2>/dev/null\` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-"
-  as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
-
-else
-  exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
-  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
-  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
-  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
-  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
-  if (eval "$as_required") 2>/dev/null; then :
-  as_have_required=yes
-else
-  as_have_required=no
-fi
-  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
-
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  as_found=:
-  case $as_dir in #(
-        /*)
-          for as_base in sh bash ksh sh5; do
-            # Try only shells that exist, to save several forks.
-            as_shell=$as_dir/$as_base
-            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
-                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  CONFIG_SHELL=$as_shell as_have_required=yes
-                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  break 2
-fi
-fi
-          done;;
-       esac
-  as_found=false
-done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
-             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
-  CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
-IFS=$as_save_IFS
-
-
-      if test "x$CONFIG_SHELL" != x; then :
-  export CONFIG_SHELL
-             # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
-    if test x$as_have_required = xno; then :
-  $as_echo "$0: This script requires a shell more modern than all"
-  $as_echo "$0: the shells that I found on your system."
-  if test x${ZSH_VERSION+set} = xset ; then
-    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
-    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
-  else
-    $as_echo "$0: Please tell bug-autoconf@gnu.org and
-$0: gary@music.mcgill.ca about your system, including any
-$0: error possibly output before this message. Then install
-$0: a modern shell, or manually run the script under such a
-$0: shell if you do have one."
-  fi
-  exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-        X"$0" : 'X\(//\)$' \| \
-        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-  as_lineno_1=$LINENO as_lineno_1a=$LINENO
-  as_lineno_2=$LINENO as_lineno_2a=$LINENO
-  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
-  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
-  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
-  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
-  # already done that, so ensure we don't try to do so again and fall
-  # in an infinite loop.  This has already happened in practice.
-  _as_can_reexec=no; export _as_can_reexec
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='        ';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='RtAudio'
-PACKAGE_TARNAME='rtaudio'
-PACKAGE_VERSION='4.1'
-PACKAGE_STRING='RtAudio 4.1'
-PACKAGE_BUGREPORT='gary@music.mcgill.ca'
-PACKAGE_URL=''
-
-ac_unique_file="RtAudio.cpp"
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include <stdio.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif
-#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif"
-
-ac_subst_vars='LTLIBOBJS
-LIBOBJS
-objects
-PULSE_LIBS
-PULSE_CFLAGS
-req
-api
-libflags
-sharedname
-sharedlib
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-object_path
-cxxflag
-cppflag
-EGREP
-GREP
-CPP
-ac_ct_CC
-CFLAGS
-CC
-AR
-RANLIB
-OBJEXT
-EXEEXT
-ac_ct_CXX
-CPPFLAGS
-LDFLAGS
-CXXFLAGS
-CXX
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
-GXX
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-enable_debug
-with_jack
-with_alsa
-with_pulse
-with_oss
-with_core
-with_asio
-with_ds
-with_wasapi
-'
-      ac_precious_vars='build_alias
-host_alias
-target_alias
-PKG_CONFIG
-PKG_CONFIG_PATH
-PKG_CONFIG_LIBDIR
-CXX
-CXXFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-CCC
-CC
-CFLAGS
-CPP
-PULSE_CFLAGS
-PULSE_LIBS'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-datadir='${datarootdir}'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
-  # If the previous option needs an argument, assign it.
-  if test -n "$ac_prev"; then
-    eval $ac_prev=\$ac_option
-    ac_prev=
-    continue
-  fi
-
-  case $ac_option in
-  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
-  *=)   ac_optarg= ;;
-  *)    ac_optarg=yes ;;
-  esac
-
-  # Accept the important Cygnus configure options, so we can diagnose typos.
-
-  case $ac_dashdash$ac_option in
-  --)
-    ac_dashdash=yes ;;
-
-  -bindir | --bindir | --bindi | --bind | --bin | --bi)
-    ac_prev=bindir ;;
-  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
-    bindir=$ac_optarg ;;
-
-  -build | --build | --buil | --bui | --bu)
-    ac_prev=build_alias ;;
-  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
-    build_alias=$ac_optarg ;;
-
-  -cache-file | --cache-file | --cache-fil | --cache-fi \
-  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
-    ac_prev=cache_file ;;
-  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
-  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
-    cache_file=$ac_optarg ;;
-
-  --config-cache | -C)
-    cache_file=config.cache ;;
-
-  -datadir | --datadir | --datadi | --datad)
-    ac_prev=datadir ;;
-  -datadir=* | --datadir=* | --datadi=* | --datad=*)
-    datadir=$ac_optarg ;;
-
-  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
-  | --dataroo | --dataro | --datar)
-    ac_prev=datarootdir ;;
-  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
-  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
-    datarootdir=$ac_optarg ;;
-
-  -disable-* | --disable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=no ;;
-
-  -docdir | --docdir | --docdi | --doc | --do)
-    ac_prev=docdir ;;
-  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
-    docdir=$ac_optarg ;;
-
-  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
-    ac_prev=dvidir ;;
-  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
-    dvidir=$ac_optarg ;;
-
-  -enable-* | --enable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=\$ac_optarg ;;
-
-  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
-  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
-  | --exec | --exe | --ex)
-    ac_prev=exec_prefix ;;
-  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
-  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
-  | --exec=* | --exe=* | --ex=*)
-    exec_prefix=$ac_optarg ;;
-
-  -gas | --gas | --ga | --g)
-    # Obsolete; use --with-gas.
-    with_gas=yes ;;
-
-  -help | --help | --hel | --he | -h)
-    ac_init_help=long ;;
-  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
-    ac_init_help=recursive ;;
-  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
-    ac_init_help=short ;;
-
-  -host | --host | --hos | --ho)
-    ac_prev=host_alias ;;
-  -host=* | --host=* | --hos=* | --ho=*)
-    host_alias=$ac_optarg ;;
-
-  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
-    ac_prev=htmldir ;;
-  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
-  | --ht=*)
-    htmldir=$ac_optarg ;;
-
-  -includedir | --includedir | --includedi | --included | --include \
-  | --includ | --inclu | --incl | --inc)
-    ac_prev=includedir ;;
-  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
-  | --includ=* | --inclu=* | --incl=* | --inc=*)
-    includedir=$ac_optarg ;;
-
-  -infodir | --infodir | --infodi | --infod | --info | --inf)
-    ac_prev=infodir ;;
-  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
-    infodir=$ac_optarg ;;
-
-  -libdir | --libdir | --libdi | --libd)
-    ac_prev=libdir ;;
-  -libdir=* | --libdir=* | --libdi=* | --libd=*)
-    libdir=$ac_optarg ;;
-
-  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
-  | --libexe | --libex | --libe)
-    ac_prev=libexecdir ;;
-  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
-  | --libexe=* | --libex=* | --libe=*)
-    libexecdir=$ac_optarg ;;
-
-  -localedir | --localedir | --localedi | --localed | --locale)
-    ac_prev=localedir ;;
-  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
-    localedir=$ac_optarg ;;
-
-  -localstatedir | --localstatedir | --localstatedi | --localstated \
-  | --localstate | --localstat | --localsta | --localst | --locals)
-    ac_prev=localstatedir ;;
-  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
-  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
-    localstatedir=$ac_optarg ;;
-
-  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
-    ac_prev=mandir ;;
-  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
-    mandir=$ac_optarg ;;
-
-  -nfp | --nfp | --nf)
-    # Obsolete; use --without-fp.
-    with_fp=no ;;
-
-  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
-  | --no-cr | --no-c | -n)
-    no_create=yes ;;
-
-  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
-    no_recursion=yes ;;
-
-  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
-  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
-  | --oldin | --oldi | --old | --ol | --o)
-    ac_prev=oldincludedir ;;
-  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
-  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
-  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
-    oldincludedir=$ac_optarg ;;
-
-  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
-    ac_prev=prefix ;;
-  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
-    prefix=$ac_optarg ;;
-
-  -program-prefix | --program-prefix | --program-prefi | --program-pref \
-  | --program-pre | --program-pr | --program-p)
-    ac_prev=program_prefix ;;
-  -program-prefix=* | --program-prefix=* | --program-prefi=* \
-  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
-    program_prefix=$ac_optarg ;;
-
-  -program-suffix | --program-suffix | --program-suffi | --program-suff \
-  | --program-suf | --program-su | --program-s)
-    ac_prev=program_suffix ;;
-  -program-suffix=* | --program-suffix=* | --program-suffi=* \
-  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
-    program_suffix=$ac_optarg ;;
-
-  -program-transform-name | --program-transform-name \
-  | --program-transform-nam | --program-transform-na \
-  | --program-transform-n | --program-transform- \
-  | --program-transform | --program-transfor \
-  | --program-transfo | --program-transf \
-  | --program-trans | --program-tran \
-  | --progr-tra | --program-tr | --program-t)
-    ac_prev=program_transform_name ;;
-  -program-transform-name=* | --program-transform-name=* \
-  | --program-transform-nam=* | --program-transform-na=* \
-  | --program-transform-n=* | --program-transform-=* \
-  | --program-transform=* | --program-transfor=* \
-  | --program-transfo=* | --program-transf=* \
-  | --program-trans=* | --program-tran=* \
-  | --progr-tra=* | --program-tr=* | --program-t=*)
-    program_transform_name=$ac_optarg ;;
-
-  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
-    ac_prev=pdfdir ;;
-  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
-    pdfdir=$ac_optarg ;;
-
-  -psdir | --psdir | --psdi | --psd | --ps)
-    ac_prev=psdir ;;
-  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
-    psdir=$ac_optarg ;;
-
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil)
-    silent=yes ;;
-
-  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
-    ac_prev=sbindir ;;
-  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
-  | --sbi=* | --sb=*)
-    sbindir=$ac_optarg ;;
-
-  -sharedstatedir | --sharedstatedir | --sharedstatedi \
-  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
-  | --sharedst | --shareds | --shared | --share | --shar \
-  | --sha | --sh)
-    ac_prev=sharedstatedir ;;
-  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
-  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
-  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
-  | --sha=* | --sh=*)
-    sharedstatedir=$ac_optarg ;;
-
-  -site | --site | --sit)
-    ac_prev=site ;;
-  -site=* | --site=* | --sit=*)
-    site=$ac_optarg ;;
-
-  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
-    ac_prev=srcdir ;;
-  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
-    srcdir=$ac_optarg ;;
-
-  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
-  | --syscon | --sysco | --sysc | --sys | --sy)
-    ac_prev=sysconfdir ;;
-  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
-  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
-    sysconfdir=$ac_optarg ;;
-
-  -target | --target | --targe | --targ | --tar | --ta | --t)
-    ac_prev=target_alias ;;
-  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
-    target_alias=$ac_optarg ;;
-
-  -v | -verbose | --verbose | --verbos | --verbo | --verb)
-    verbose=yes ;;
-
-  -version | --version | --versio | --versi | --vers | -V)
-    ac_init_version=: ;;
-
-  -with-* | --with-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=\$ac_optarg ;;
-
-  -without-* | --without-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=no ;;
-
-  --x)
-    # Obsolete; use --with-x.
-    with_x=yes ;;
-
-  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
-  | --x-incl | --x-inc | --x-in | --x-i)
-    ac_prev=x_includes ;;
-  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
-  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
-    x_includes=$ac_optarg ;;
-
-  -x-libraries | --x-libraries | --x-librarie | --x-librari \
-  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
-    ac_prev=x_libraries ;;
-  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
-  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
-    x_libraries=$ac_optarg ;;
-
-  -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
-    ;;
-
-  *=*)
-    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
-    # Reject names that are not valid shell variable names.
-    case $ac_envvar in #(
-      '' | [0-9]* | *[!_$as_cr_alnum]* )
-      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
-    esac
-    eval $ac_envvar=\$ac_optarg
-    export $ac_envvar ;;
-
-  *)
-    # FIXME: should be removed in autoconf 3.0.
-    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
-    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
-      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
-    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
-    ;;
-
-  esac
-done
-
-if test -n "$ac_prev"; then
-  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
-  case $enable_option_checking in
-    no) ;;
-    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
-    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
-  esac
-fi
-
-# Check all directory arguments for consistency.
-for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
-               datadir sysconfdir sharedstatedir localstatedir includedir \
-               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir
-do
-  eval ac_val=\$$ac_var
-  # Remove trailing slashes.
-  case $ac_val in
-    */ )
-      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
-      eval $ac_var=\$ac_val;;
-  esac
-  # Be sure to have absolute directory names.
-  case $ac_val in
-    [\\/$]* | ?:[\\/]* )  continue;;
-    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
-  esac
-  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
-  if test "x$build_alias" = x; then
-    cross_compiling=maybe
-  elif test "x$build_alias" != "x$host_alias"; then
-    cross_compiling=yes
-  fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
-  ac_srcdir_defaulted=yes
-  # Try the directory containing this script, then the parent directory.
-  ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_myself" : 'X\(//\)[^/]' \| \
-        X"$as_myself" : 'X\(//\)$' \| \
-        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-  srcdir=$ac_confdir
-  if test ! -r "$srcdir/$ac_unique_file"; then
-    srcdir=..
-  fi
-else
-  ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
-  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
-       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
-       pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
-  srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
-  eval ac_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_env_${ac_var}_value=\$${ac_var}
-  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
-  # Omit some internal or obsolete options to make the list less imposing.
-  # This message is too long to be a string in the A/UX 3.1 sh.
-  cat <<_ACEOF
-\`configure' configures RtAudio 4.1 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE.  See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
-  -h, --help              display this help and exit
-      --help=short        display options specific to this package
-      --help=recursive    display the short help of all the included packages
-  -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking ...' messages
-      --cache-file=FILE   cache test results in FILE [disabled]
-  -C, --config-cache      alias for \`--cache-file=config.cache'
-  -n, --no-create         do not create output files
-      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
-
-Installation directories:
-  --prefix=PREFIX         install architecture-independent files in PREFIX
-                          [$ac_default_prefix]
-  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
-                          [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/rtaudio]
-  --htmldir=DIR           html documentation [DOCDIR]
-  --dvidir=DIR            dvi documentation [DOCDIR]
-  --pdfdir=DIR            pdf documentation [DOCDIR]
-  --psdir=DIR             ps documentation [DOCDIR]
-_ACEOF
-
-  cat <<\_ACEOF
-
-System types:
-  --build=BUILD     configure for building on BUILD [guessed]
-  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
-  case $ac_init_help in
-     short | recursive ) echo "Configuration of RtAudio 4.1:";;
-   esac
-  cat <<\_ACEOF
-
-Optional Features:
-  --disable-option-checking  ignore unrecognized --enable/--with options
-  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
-  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --enable-debug = enable various debug output
-
-Optional Packages:
-  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
-  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --with-jack = choose JACK server support (mac and linux only)
-  --with-alsa = choose native ALSA API support (linux only)
-  --with-pulse = choose PulseAudio API support (linux only)
-  --with-oss = choose OSS API support (linux only)
-  --with-jack = choose JACK server support (unix only)
-  --with-core = choose CoreAudio API support (mac only)
-  --with-asio = choose ASIO API support (windoze only)
-  --with-ds = choose DirectSound API support (windoze only)
-  --with-wasapi = choose Windows Audio Session API support (windoze only)
-
-Some influential environment variables:
-  PKG_CONFIG  path to pkg-config utility
-  PKG_CONFIG_PATH
-              directories to add to pkg-config's search path
-  PKG_CONFIG_LIBDIR
-              path overriding pkg-config's built-in search path
-  CXX         C++ compiler command
-  CXXFLAGS    C++ compiler flags
-  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
-              nonstandard directory <lib dir>
-  LIBS        libraries to pass to the linker, e.g. -l<library>
-  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
-              you have headers in a nonstandard directory <include dir>
-  CC          C compiler command
-  CFLAGS      C compiler flags
-  CPP         C preprocessor
-  PULSE_CFLAGS
-              C compiler flags for PULSE, overriding pkg-config
-  PULSE_LIBS  linker flags for PULSE, overriding pkg-config
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to <gary@music.mcgill.ca>.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
-  # If there are subdirs, report their specific --help.
-  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
-    test -d "$ac_dir" ||
-      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
-      continue
-    ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-    cd "$ac_dir" || { ac_status=$?; continue; }
-    # Check for guested configure.
-    if test -f "$ac_srcdir/configure.gnu"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
-    elif test -f "$ac_srcdir/configure"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure" --help=recursive
-    else
-      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
-    fi || ac_status=$?
-    cd "$ac_pwd" || { ac_status=$?; break; }
-  done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
-  cat <<\_ACEOF
-RtAudio configure 4.1
-generated by GNU Autoconf 2.69
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
-  exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_cxx_try_compile LINENO
-# ----------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_cxx_try_compile ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext
-  if { { ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compile") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=1
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_cxx_try_compile
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext
-  if { { ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compile") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=1
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } > conftest.i && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-    ac_retval=1
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_cpp
-
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
-ac_fn_c_try_run ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-       $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=$ac_status
-fi
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if eval \${$3+:} false; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_header_compiler=yes
-else
-  ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  ac_header_preproc=yes
-else
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
-  yes:no: )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ----------------------------------- ##
-## Report this to gary@music.mcgill.ca ##
-## ----------------------------------- ##"
-     ) | sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_mongrel
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext conftest$ac_exeext
-  if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        test -x conftest$ac_exeext
-       }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=1
-fi
-  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
-  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
-  # interfere with the next link command; also delete a directory that is
-  # left behind by Apple's compiler.  We do this before executing the actions.
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $2 (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main ()
-{
-return $2 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by RtAudio $as_me 4.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  $ $0 $@
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
-
-/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
-/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
-/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    $as_echo "PATH: $as_dir"
-  done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
-  for ac_arg
-  do
-    case $ac_arg in
-    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
-    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-    | -silent | --silent | --silen | --sile | --sil)
-      continue ;;
-    *\'*)
-      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    esac
-    case $ac_pass in
-    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
-    2)
-      as_fn_append ac_configure_args1 " '$ac_arg'"
-      if test $ac_must_keep_next = true; then
-       ac_must_keep_next=false # Got value, back to normal.
-      else
-       case $ac_arg in
-         *=* | --config-cache | -C | -disable-* | --disable-* \
-         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
-         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
-         | -with-* | --with-* | -without-* | --without-* | --x)
-           case "$ac_configure_args0 " in
-             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
-           esac
-           ;;
-         -* ) ac_must_keep_next=true ;;
-       esac
-      fi
-      as_fn_append ac_configure_args " '$ac_arg'"
-      ;;
-    esac
-  done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log.  We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
-  # Save into config.log some information that might help in debugging.
-  {
-    echo
-
-    $as_echo "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
-    echo
-    # The following way of writing the cache mishandles newlines in values,
-(
-  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-  (set) 2>&1 |
-    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      sed -n \
-       "s/'\''/'\''\\\\'\'''\''/g;
-         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
-      ;; #(
-    *)
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-)
-    echo
-
-    $as_echo "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
-    echo
-    for ac_var in $ac_subst_vars
-    do
-      eval ac_val=\$$ac_var
-      case $ac_val in
-      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-      esac
-      $as_echo "$ac_var='\''$ac_val'\''"
-    done | sort
-    echo
-
-    if test -n "$ac_subst_files"; then
-      $as_echo "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
-      echo
-      for ac_var in $ac_subst_files
-      do
-       eval ac_val=\$$ac_var
-       case $ac_val in
-       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-       esac
-       $as_echo "$ac_var='\''$ac_val'\''"
-      done | sort
-      echo
-    fi
-
-    if test -s confdefs.h; then
-      $as_echo "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
-      echo
-      cat confdefs.h
-      echo
-    fi
-    test "$ac_signal" != 0 &&
-      $as_echo "$as_me: caught signal $ac_signal"
-    $as_echo "$as_me: exit $exit_status"
-  } >&5
-  rm -f core *.core core.conftest.* &&
-    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
-    exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-$as_echo "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
-if test -n "$CONFIG_SITE"; then
-  # We do not want a PATH search for config.site.
-  case $CONFIG_SITE in #((
-    -*)  ac_site_file1=./$CONFIG_SITE;;
-    */*) ac_site_file1=$CONFIG_SITE;;
-    *)   ac_site_file1=./$CONFIG_SITE;;
-  esac
-elif test "x$prefix" != xNONE; then
-  ac_site_file1=$prefix/share/config.site
-  ac_site_file2=$prefix/etc/config.site
-else
-  ac_site_file1=$ac_default_prefix/share/config.site
-  ac_site_file2=$ac_default_prefix/etc/config.site
-fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
-do
-  test "x$ac_site_file" = xNONE && continue
-  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
-    sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file" \
-      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
-  fi
-done
-
-if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special files
-  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
-  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
-    case $cache_file in
-      [\\/]* | ?:[\\/]* ) . "$cache_file";;
-      *)                      . "./$cache_file";;
-    esac
-  fi
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
-  >$cache_file
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
-  eval ac_old_set=\$ac_cv_env_${ac_var}_set
-  eval ac_new_set=\$ac_env_${ac_var}_set
-  eval ac_old_val=\$ac_cv_env_${ac_var}_value
-  eval ac_new_val=\$ac_env_${ac_var}_value
-  case $ac_old_set,$ac_new_set in
-    set,)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,set)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,);;
-    *)
-      if test "x$ac_old_val" != "x$ac_new_val"; then
-       # differences in whitespace do not lead to failure.
-       ac_old_val_w=`echo x $ac_old_val`
-       ac_new_val_w=`echo x $ac_new_val`
-       if test "$ac_old_val_w" != "$ac_new_val_w"; then
-         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
-         ac_cache_corrupted=:
-       else
-         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
-         eval $ac_var=\$ac_old_val
-       fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
-$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
-       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
-$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
-      fi;;
-  esac
-  # Pass precious variables to config.status.
-  if test "$ac_new_set" = set; then
-    case $ac_new_val in
-    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
-    *) ac_arg=$ac_var=$ac_new_val ;;
-    esac
-    case " $ac_configure_args " in
-      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
-    esac
-  fi
-done
-if $ac_cache_corrupted; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-ac_aux_dir=
-for ac_dir in config "$srcdir"/config; do
-  if test -f "$ac_dir/install-sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f "$ac_dir/install.sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  elif test -f "$ac_dir/shtool"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/shtool install -c"
-    break
-  fi
-done
-if test -z "$ac_aux_dir"; then
-  as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
-
-
-
-ac_config_files="$ac_config_files rtaudio-config librtaudio.pc Makefile tests/Makefile"
-
-
-# Fill GXX with something before test.
-GXX="no"
-
-
-
-
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-       if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-fi
-
-fi
-if test -n "$PKG_CONFIG"; then
-       _pkg_min_version=0.9.0
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       else
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               PKG_CONFIG=""
-       fi
-fi
-
-
-
-# Checks for programs.
-ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-if test -z "$CXX"; then
-  if test -n "$CCC"; then
-    CXX=$CCC
-  else
-    if test -n "$ac_tool_prefix"; then
-  for ac_prog in g++ CC c++ cxx
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CXX"; then
-  ac_cv_prog_CXX="$CXX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CXX=$ac_cv_prog_CXX
-if test -n "$CXX"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
-$as_echo "$CXX" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$CXX" && break
-  done
-fi
-if test -z "$CXX"; then
-  ac_ct_CXX=$CXX
-  for ac_prog in g++ CC c++ cxx
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CXX"; then
-  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CXX="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
-if test -n "$ac_ct_CXX"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
-$as_echo "$ac_ct_CXX" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_CXX" && break
-done
-
-  if test "x$ac_ct_CXX" = x; then
-    CXX="g++"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CXX=$ac_ct_CXX
-  fi
-fi
-
-  fi
-fi
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
-  { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    sed '10a\
-... rest of stderr output deleted ...
-         10q' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5
-$as_echo_n "checking whether the C++ compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
-  esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link_default") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile.  We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
-       ;;
-    [ab].out )
-       # We found the default executable, but exeext='' is most
-       # certainly right.
-       break;;
-    *.* )
-       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
-       then :; else
-          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-       fi
-       # We set ac_cv_exeext here because the later test for it is not
-       # safe: cross compilers may not add the suffix if given an `-o'
-       # argument, so we may need to know it at that point already.
-       # Even if this section looks crufty: it has the advantage of
-       # actually working.
-       break;;
-    * )
-       break;;
-  esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else
-  ac_file=''
-fi
-if test -z "$ac_file"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C++ compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5
-$as_echo_n "checking for C++ compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-         break;;
-    * ) break;;
-  esac
-done
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdio.h>
-int
-main ()
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
-  { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-  if { ac_try='./conftest$ac_cv_exeext'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-       cross_compiling=yes
-    else
-       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C++ compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
-    fi
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compile") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  for ac_file in conftest.o conftest.obj conftest.*; do
-  test -f "$ac_file" || continue;
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
-    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
-       break;;
-  esac
-done
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
-$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if ${ac_cv_cxx_compiler_gnu+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-#ifndef __GNUC__
-       choke me
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_compiler_gnu=yes
-else
-  ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
-$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
-  GXX=yes
-else
-  GXX=
-fi
-ac_test_CXXFLAGS=${CXXFLAGS+set}
-ac_save_CXXFLAGS=$CXXFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
-$as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if ${ac_cv_prog_cxx_g+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
-   ac_cxx_werror_flag=yes
-   ac_cv_prog_cxx_g=no
-   CXXFLAGS="-g"
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_cv_prog_cxx_g=yes
-else
-  CXXFLAGS=""
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-
-else
-  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
-        CXXFLAGS="-g"
-        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_cv_prog_cxx_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
-$as_echo "$ac_cv_prog_cxx_g" >&6; }
-if test "$ac_test_CXXFLAGS" = set; then
-  CXXFLAGS=$ac_save_CXXFLAGS
-elif test $ac_cv_prog_cxx_g = yes; then
-  if test "$GXX" = yes; then
-    CXXFLAGS="-g -O2"
-  else
-    CXXFLAGS="-g"
-  fi
-else
-  if test "$GXX" = yes; then
-    CXXFLAGS="-O2"
-  else
-    CXXFLAGS=
-  fi
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$RANLIB"; then
-  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
-  ac_ct_RANLIB=$RANLIB
-  # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_RANLIB"; then
-  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_RANLIB" = x; then
-    RANLIB=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    RANLIB=$ac_ct_RANLIB
-  fi
-else
-  RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-# Extract the first word of "ar", so it can be a program name with args.
-set dummy ar; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_AR+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $AR in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_AR="$AR" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  test -z "$ac_cv_path_AR" && ac_cv_path_AR="no"
-  ;;
-esac
-fi
-AR=$ac_cv_path_AR
-if test -n "$AR"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-$as_echo "$AR" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-if [ $AR = "no" ] ; then
-    as_fn_error $? "\"Could not find ar - needed to create a library\"" "$LINENO" 5;
-fi
-
-# Checks for header files.
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
-  ac_ct_CC=$CC
-  # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CC="gcc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-else
-  CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
-          if test -n "$ac_tool_prefix"; then
-    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="${ac_tool_prefix}cc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  fi
-fi
-if test -z "$CC"; then
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
-       ac_prog_rejected=yes
-       continue
-     fi
-    ac_cv_prog_CC="cc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
-  # We found a bogon in the path, so make sure we never use it.
-  set dummy $ac_cv_prog_CC
-  shift
-  if test $# != 0; then
-    # We chose a different compiler from the bogus one.
-    # However, it has the same basename, so the bogon will be chosen
-    # first if we set CC to just the basename; use the full file name.
-    shift
-    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
-  fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
-  if test -n "$ac_tool_prefix"; then
-  for ac_prog in cl.exe
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$CC" && break
-  done
-fi
-if test -z "$CC"; then
-  ac_ct_CC=$CC
-  for ac_prog in cl.exe
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CC="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_CC" && break
-done
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-fi
-
-fi
-
-
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
-
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
-  { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    sed '10a\
-... rest of stderr output deleted ...
-         10q' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-#ifndef __GNUC__
-       choke me
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_compiler_gnu=yes
-else
-  ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
-  GCC=yes
-else
-  GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_save_c_werror_flag=$ac_c_werror_flag
-   ac_c_werror_flag=yes
-   ac_cv_prog_cc_g=no
-   CFLAGS="-g"
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_g=yes
-else
-  CFLAGS=""
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
-  ac_c_werror_flag=$ac_save_c_werror_flag
-        CFLAGS="-g"
-        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-   ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
-  CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
-  if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
-  else
-    CFLAGS="-g"
-  fi
-else
-  if test "$GCC" = yes; then
-    CFLAGS="-O2"
-  else
-    CFLAGS=
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
-     char **p;
-     int i;
-{
-  return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
-  char *s;
-  va_list v;
-  va_start (v,p);
-  s = g (p, va_arg (v,int));
-  va_end (v);
-  return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
-   function prototypes and stuff, but not '\xHH' hex character constants.
-   These don't provoke an error unfortunately, instead are silently treated
-   as 'x'.  The following induces an error, until -std is added to get
-   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
-   array size at least.  It's necessary to write '\x00'==0 to get something
-   that's true only with -std.  */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
-   inside strings and character constants.  */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
-  ;
-  return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
-       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
-  CC="$ac_save_CC $ac_arg"
-  if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
-  test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
-  x)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
-  xno)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
-  *)
-    CC="$CC $ac_cv_prog_cc_c89"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
-fi
-if test -z "$CPP"; then
-  if ${ac_cv_prog_CPP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-      # Double quotes because CPP needs to be expanded
-    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
-    do
-      ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-
-else
-  # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
-else
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
-  break
-fi
-
-    done
-    ac_cv_prog_CPP=$CPP
-
-fi
-  CPP=$ac_cv_prog_CPP
-else
-  ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-
-else
-  # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
-else
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$GREP"; then
-  ac_path_GREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in grep ggrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
-  # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'GREP' >> "conftest.nl"
-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_GREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_GREP="$ac_path_GREP"
-      ac_path_GREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_GREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_GREP"; then
-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
-   then ac_cv_path_EGREP="$GREP -E"
-   else
-     if test -z "$EGREP"; then
-  ac_path_EGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in egrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
-  # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'EGREP' >> "conftest.nl"
-    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_EGREP="$ac_path_EGREP"
-      ac_path_EGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_EGREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_EGREP"; then
-    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_EGREP=$EGREP
-fi
-
-   fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_header_stdc=yes
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-  if test "$cross_compiling" = yes; then :
-  :
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
-                  (('a' <= (c) && (c) <= 'i') \
-                    || ('j' <= (c) && (c) <= 'r') \
-                    || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
-  int i;
-  for (i = 0; i < 256; i++)
-    if (XOR (islower (i), ISLOWER (i))
-       || toupper (i) != TOUPPER (i))
-      return 2;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
-                 inttypes.h stdint.h unistd.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-for ac_header in sys/ioctl.h unistd.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-# Check for debug
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile debug version" >&5
-$as_echo_n "checking whether to compile debug version... " >&6; }
-# Check whether --enable-debug was given.
-if test "${enable_debug+set}" = set; then :
-  enableval=$enable_debug; cppflag=-D__RTAUDIO_DEBUG__
- cxxflag=-g
- object_path=Debug
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
-  cppflag=
- cxxflag=-O2
- object_path=Release
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-
-# Checks for functions
-ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
-if test "x$ac_cv_func_gettimeofday" = xyes; then :
-  cppflag="$cppflag -DHAVE_GETTIMEOFDAY"
-fi
-
-
-# Set paths if prefix is defined
-if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then
-  LIBS="$LIBS -L$prefix/lib"
-  CPPFLAGS="$CPPFLAGS -I$prefix/include"
-fi
-
-# For -I and -D flags
-CPPFLAGS="$CPPFLAGS $cppflag"
-
-# For debugging and optimization ... overwrite default because it has both -g and -O2
-#CXXFLAGS="$CXXFLAGS $cxxflag"
-CXXFLAGS="$cxxflag"
-
-# Check compiler and use -Wall if gnu.
-if test $GXX = "yes" ; then
-  cxxflag="-Wall -Wextra"
-
-fi
-
-CXXFLAGS="$CXXFLAGS $cxxflag"
-
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
-  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
-  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$host_alias" = x; then
-  ac_cv_host=$ac_cv_build
-else
-  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-
-sharedlib="librtaudio.so"
-
-sharedname="librtaudio.so.\$(RELEASE)"
-
-libflags="-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)"
-
-case $host in
-  *-apple*)
-  sharedlib="librtaudio.dylib"
-
-  sharedname="librtaudio.\$(RELEASE).dylib"
-
-  libflags="-dynamiclib -o librtaudio.\$(RELEASE).dylib"
-
-esac
-
-# Checks for package options and external software
-api=""
-
-req=""
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for audio API" >&5
-$as_echo_n "checking for audio API... " >&6; }
-case $host in
-  *-*-netbsd*)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5
-$as_echo "using OSS" >&6; }
-    api="$api -D__LINUX_OSS__"
-    LIBS="$LIBS -lossaudio"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
-$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
-if ${ac_cv_lib_pthread_pthread_create+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_create ();
-int
-main ()
-{
-return pthread_create ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_pthread_pthread_create=yes
-else
-  ac_cv_lib_pthread_pthread_create=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
-$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBPTHREAD 1
-_ACEOF
-
-  LIBS="-lpthread $LIBS"
-
-else
-  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
-fi
-
-  ;;
-
-  *-*-linux*)
-
-# Check whether --with-jack was given.
-if test "${with_jack+set}" = set; then :
-  withval=$with_jack;
-    api="$api -D__UNIX_JACK__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5
-$as_echo "using JACK" >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5
-$as_echo_n "checking for jack_client_open in -ljack... " >&6; }
-if ${ac_cv_lib_jack_jack_client_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ljack  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char jack_client_open ();
-int
-main ()
-{
-return jack_client_open ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_jack_jack_client_open=yes
-else
-  ac_cv_lib_jack_jack_client_open=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5
-$as_echo "$ac_cv_lib_jack_jack_client_open" >&6; }
-if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBJACK 1
-_ACEOF
-
-  LIBS="-ljack $LIBS"
-
-else
-  as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5
-fi
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
-$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
-if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lasound  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char snd_pcm_open ();
-int
-main ()
-{
-return snd_pcm_open ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_asound_snd_pcm_open=yes
-else
-  ac_cv_lib_asound_snd_pcm_open=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
-$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
-if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBASOUND 1
-_ACEOF
-
-  LIBS="-lasound $LIBS"
-
-else
-  as_fn_error $? "Jack support also requires the asound library!" "$LINENO" 5
-fi
-
-fi
-
-
-  # Look for ALSA flag
-
-# Check whether --with-alsa was given.
-if test "${with_alsa+set}" = set; then :
-  withval=$with_alsa;
-    api="$api -D__LINUX_ALSA__"
-    req="$req alsa"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5
-$as_echo "using ALSA" >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
-$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
-if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lasound  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char snd_pcm_open ();
-int
-main ()
-{
-return snd_pcm_open ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_asound_snd_pcm_open=yes
-else
-  ac_cv_lib_asound_snd_pcm_open=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
-$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
-if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBASOUND 1
-_ACEOF
-
-  LIBS="-lasound $LIBS"
-
-else
-  as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5
-fi
-
-fi
-
-
-  # Look for PULSE flag
-
-# Check whether --with-pulse was given.
-if test "${with_pulse+set}" = set; then :
-  withval=$with_pulse;
-    api="$api -D__LINUX_PULSE__"
-    req="$req libpulse-simple"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using PulseAudio" >&5
-$as_echo "using PulseAudio" >&6; }
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PULSE" >&5
-$as_echo_n "checking for PULSE... " >&6; }
-
-if test -n "$PULSE_CFLAGS"; then
-    pkg_cv_PULSE_CFLAGS="$PULSE_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PULSE_CFLAGS=`$PKG_CONFIG --cflags "libpulse-simple" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$PULSE_LIBS"; then
-    pkg_cv_PULSE_LIBS="$PULSE_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PULSE_LIBS=`$PKG_CONFIG --libs "libpulse-simple" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               PULSE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse-simple" 2>&1`
-        else
-               PULSE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse-simple" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$PULSE_PKG_ERRORS" >&5
-
-       as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5
-else
-       PULSE_CFLAGS=$pkg_cv_PULSE_CFLAGS
-       PULSE_LIBS=$pkg_cv_PULSE_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-fi
-        LIBS="$LIBS `pkg-config --libs libpulse-simple`"
-fi
-
-
-  # Look for OSS flag
-
-# Check whether --with-oss was given.
-if test "${with_oss+set}" = set; then :
-  withval=$with_oss;
-    api="$api -D__LINUX_OSS__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5
-$as_echo "using OSS" >&6; }
-fi
-
-
-  # If no audio api flags specified, use ALSA
-  if test "$api" == ""; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5
-$as_echo "using ALSA" >&6; }
-    api=-D__LINUX_ALSA__
-
-    req="$req alsa"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
-$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; }
-if ${ac_cv_lib_asound_snd_pcm_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lasound  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char snd_pcm_open ();
-int
-main ()
-{
-return snd_pcm_open ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_asound_snd_pcm_open=yes
-else
-  ac_cv_lib_asound_snd_pcm_open=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
-$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; }
-if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBASOUND 1
-_ACEOF
-
-  LIBS="-lasound $LIBS"
-
-else
-  as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5
-fi
-
-  fi
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
-$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
-if ${ac_cv_lib_pthread_pthread_create+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_create ();
-int
-main ()
-{
-return pthread_create ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_pthread_pthread_create=yes
-else
-  ac_cv_lib_pthread_pthread_create=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
-$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBPTHREAD 1
-_ACEOF
-
-  LIBS="-lpthread $LIBS"
-
-else
-  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
-fi
-
-  ;;
-
-  *-apple*)
-
-# Check whether --with-jack was given.
-if test "${with_jack+set}" = set; then :
-  withval=$with_jack;
-    api="$api -D__UNIX_JACK__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5
-$as_echo "using JACK" >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5
-$as_echo_n "checking for jack_client_open in -ljack... " >&6; }
-if ${ac_cv_lib_jack_jack_client_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ljack  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char jack_client_open ();
-int
-main ()
-{
-return jack_client_open ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_jack_jack_client_open=yes
-else
-  ac_cv_lib_jack_jack_client_open=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5
-$as_echo "$ac_cv_lib_jack_jack_client_open" >&6; }
-if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBJACK 1
-_ACEOF
-
-  LIBS="-ljack $LIBS"
-
-else
-  as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5
-fi
-
-fi
-
-
-#    AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] )
-#    LIBS="$LIBS -framework jackmp" ], )
-
-
-  # Look for Core flag
-
-# Check whether --with-core was given.
-if test "${with_core+set}" = set; then :
-  withval=$with_core;
-    api="$api -D__MACOSX_CORE__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5
-$as_echo "using CoreAudio" >&6; }
-    ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default"
-if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then :
-
-else
-  as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5
-fi
-
-
-    LIBS="$LIBS -framework CoreAudio -framework CoreFoundation"
-fi
-
-
-  # If no audio api flags specified, use CoreAudio
-  if test "$api" == "";  then
-    api=-D__MACOSX_CORE__
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5
-$as_echo "using CoreAudio" >&6; }
-    ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default"
-if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then :
-
-else
-  as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5
-fi
-
-
-    LIBS="-framework CoreAudio -framework CoreFoundation"
-
-  fi
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
-$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
-if ${ac_cv_lib_pthread_pthread_create+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_create ();
-int
-main ()
-{
-return pthread_create ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_pthread_pthread_create=yes
-else
-  ac_cv_lib_pthread_pthread_create=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
-$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBPTHREAD 1
-_ACEOF
-
-  LIBS="-lpthread $LIBS"
-
-else
-  as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5
-fi
-
-  ;;
-
-  *-mingw32*)
-
-# Check whether --with-asio was given.
-if test "${with_asio+set}" = set; then :
-  withval=$with_asio;
-    api="$api -D__WINDOWS_ASIO__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ASIO" >&5
-$as_echo "using ASIO" >&6; }
-    objects="asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"
-
-fi
-
-
-  # Look for DirectSound flag
-
-# Check whether --with-ds was given.
-if test "${with_ds+set}" = set; then :
-  withval=$with_ds;
-    api="$api -D__WINDOWS_DS__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5
-$as_echo "using DirectSound" >&6; }
-    LIBS="-ldsound -lwinmm $LIBS"
-fi
-
-
-  # Look for WASAPI flag
-
-# Check whether --with-wasapi was given.
-if test "${with_wasapi+set}" = set; then :
-  withval=$with_wasapi;
-    api="$api -D__WINDOWS_WASAPI__"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using WASAPI" >&5
-$as_echo "using WASAPI" >&6; }
-    LIBS="-lwinmm -luuid -lksuser $LIBS"
-fi
-
-
-  # If no audio api flags specified, use DS
-  if test "$api" == ""; then
-    api=-D__WINDOWS_DS__
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5
-$as_echo "using DirectSound" >&6; }
-    LIBS="-ldsound -lwinmm $LIBS"
-  fi
-
-  LIBS="-lole32 $LIBS"
-  ;;
-
-  *)
-  # Default case for unknown realtime systems.
-  as_fn_error $? "Unknown system type for realtime support!" "$LINENO" 5
-  ;;
-esac
-
-CPPFLAGS="$CPPFLAGS $api"
-
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems.  If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
-  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-
-  (set) 2>&1 |
-    case $as_nl`(ac_space=' '; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes: double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \.
-      sed -n \
-       "s/'/'\\\\''/g;
-         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
-      ;; #(
-    *)
-      # `set' quotes correctly as required by POSIX, so do not add quotes.
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-) |
-  sed '
-     /^ac_cv_env_/b end
-     t clear
-     :clear
-     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
-     t end
-     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
-     :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
-  if test -w "$cache_file"; then
-    if test "x$cache_file" != "x/dev/null"; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
-      if test ! -f "$cache_file" || test -h "$cache_file"; then
-       cat confcache >"$cache_file"
-      else
-        case $cache_file in #(
-        */* | ?:*)
-         mv -f confcache "$cache_file"$$ &&
-         mv -f "$cache_file"$$ "$cache_file" ;; #(
-        *)
-         mv -f confcache "$cache_file" ;;
-       esac
-      fi
-    fi
-  else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
-  fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section.  Otherwise,
-# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
-t clear
-:clear
-s/^[    ]*#[    ]*define[       ][      ]*\([^  (][^    (]*([^)]*)\)[   ]*\(.*\)/-D\1=\2/g
-t quote
-s/^[    ]*#[    ]*define[       ][      ]*\([^  ][^     ]*\)[   ]*\(.*\)/-D\1=\2/g
-t quote
-b any
-:quote
-s/[     `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\[/\\&/g
-s/\]/\\&/g
-s/\$/$$/g
-H
-:any
-${
-       g
-       s/^\n//
-       s/\n/ /g
-       p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
-
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
-  # 1. Remove the extension, and $U if already installed.
-  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
-  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
-  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
-  #    will be set to the directory where LIBOBJS objects are built.
-  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
-  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-       expr "X$arg" : "X\\(.*\\)$as_nl";
-       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""       $as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-        X"$0" : 'X\(//\)$' \| \
-        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='        ';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by RtAudio $as_me 4.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  CONFIG_FILES    = $CONFIG_FILES
-  CONFIG_HEADERS  = $CONFIG_HEADERS
-  CONFIG_LINKS    = $CONFIG_LINKS
-  CONFIG_COMMANDS = $CONFIG_COMMANDS
-  $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration.  Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
-  -h, --help       print this help, then exit
-  -V, --version    print version number and configuration settings, then exit
-      --config     print configuration, then exit
-  -q, --quiet, --silent
-                   do not print progress messages
-  -d, --debug      don't remove temporary files
-      --recheck    update $as_me by reconfiguring in the same conditions
-      --file=FILE[:TEMPLATE]
-                   instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Report bugs to <gary@music.mcgill.ca>."
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
-ac_cs_version="\\
-RtAudio config.status 4.1
-configured by $0, generated by GNU Autoconf 2.69,
-  with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
-  case $1 in
-  --*=?*)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
-    ac_shift=:
-    ;;
-  --*=)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=
-    ac_shift=:
-    ;;
-  *)
-    ac_option=$1
-    ac_optarg=$2
-    ac_shift=shift
-    ;;
-  esac
-
-  case $ac_option in
-  # Handling of the options.
-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
-    ac_cs_recheck=: ;;
-  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
-    $as_echo "$ac_cs_version"; exit ;;
-  --config | --confi | --conf | --con | --co | --c )
-    $as_echo "$ac_cs_config"; exit ;;
-  --debug | --debu | --deb | --de | --d | -d )
-    debug=: ;;
-  --file | --fil | --fi | --f )
-    $ac_shift
-    case $ac_optarg in
-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    '') as_fn_error $? "missing file argument" ;;
-    esac
-    as_fn_append CONFIG_FILES " '$ac_optarg'"
-    ac_need_defaults=false;;
-  --he | --h |  --help | --hel | -h )
-    $as_echo "$ac_cs_usage"; exit ;;
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil | --si | --s)
-    ac_cs_silent=: ;;
-
-  # This is an error.
-  -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
-  *) as_fn_append ac_config_targets " $1"
-     ac_need_defaults=false ;;
-
-  esac
-  shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
-  exec 6>/dev/null
-  ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
-  shift
-  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
-  CONFIG_SHELL='$SHELL'
-  export CONFIG_SHELL
-  exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
-  echo
-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-  $as_echo "$ac_log"
-} >&5
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
-  case $ac_config_target in
-    "rtaudio-config") CONFIG_FILES="$CONFIG_FILES rtaudio-config" ;;
-    "librtaudio.pc") CONFIG_FILES="$CONFIG_FILES librtaudio.pc" ;;
-    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
-
-  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
-  esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used.  Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
-fi
-
-# Have a temporary directory for convenience.  Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
-  tmp= ac_tmp=
-  trap 'exit_status=$?
-  : "${ac_tmp:=$tmp}"
-  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
-  trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
-  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
-  test -d "$tmp"
-}  ||
-{
-  tmp=./conf$$-$RANDOM
-  (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
-  eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
-  ac_cs_awk_cr='\\r'
-else
-  ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
-  echo "cat >conf$$subs.awk <<_ACEOF" &&
-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
-  echo "_ACEOF"
-} >conf$$subs.sh ||
-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
-  . ./conf$$subs.sh ||
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
-  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
-  if test $ac_delim_n = $ac_delim_num; then
-    break
-  elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-  else
-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
-  fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
-  N
-  s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
-  for (key in S) S_is_set[key] = 1
-  FS = "\a"
-
-}
-{
-  line = $ 0
-  nfields = split(line, field, "@")
-  substed = 0
-  len = length(field[1])
-  for (i = 2; i < nfields; i++) {
-    key = field[i]
-    keylen = length(key)
-    if (S_is_set[key]) {
-      value = S[key]
-      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
-      len += length(value) + length(field[++i])
-      substed = 1
-    } else
-      len += 1 + keylen
-  }
-
-  print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
-  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
-  cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
-  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
-h
-s///
-s/^/:/
-s/[     ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[  ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[      ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-
-eval set X "  :F $CONFIG_FILES      "
-shift
-for ac_tag
-do
-  case $ac_tag in
-  :[FHLC]) ac_mode=$ac_tag; continue;;
-  esac
-  case $ac_mode$ac_tag in
-  :[FHL]*:*);;
-  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
-  :[FH]-) ac_tag=-:-;;
-  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
-  esac
-  ac_save_IFS=$IFS
-  IFS=:
-  set x $ac_tag
-  IFS=$ac_save_IFS
-  shift
-  ac_file=$1
-  shift
-
-  case $ac_mode in
-  :L) ac_source=$1;;
-  :[FH])
-    ac_file_inputs=
-    for ac_f
-    do
-      case $ac_f in
-      -) ac_f="$ac_tmp/stdin";;
-      *) # Look for the file first in the build tree, then in the source tree
-        # (if the path is not absolute).  The absolute path cannot be DOS-style,
-        # because $ac_f cannot contain `:'.
-        test -f "$ac_f" ||
-          case $ac_f in
-          [\\/$]*) false;;
-          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
-          esac ||
-          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
-      esac
-      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
-      as_fn_append ac_file_inputs " '$ac_f'"
-    done
-
-    # Let's still pretend it is `configure' which instantiates (i.e., don't
-    # use $as_me), people would be surprised to read:
-    #    /* config.h.  Generated by config.status.  */
-    configure_input='Generated from '`
-         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
-       `' by configure.'
-    if test x"$ac_file" != x-; then
-      configure_input="$ac_file.  $configure_input"
-      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
-    fi
-    # Neutralize special characters interpreted by sed in replacement strings.
-    case $configure_input in #(
-    *\&* | *\|* | *\\* )
-       ac_sed_conf_input=`$as_echo "$configure_input" |
-       sed 's/[\\\\&|]/\\\\&/g'`;; #(
-    *) ac_sed_conf_input=$configure_input;;
-    esac
-
-    case $ac_tag in
-    *:-:* | *:-) cat >"$ac_tmp/stdin" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
-    esac
-    ;;
-  esac
-
-  ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$ac_file" : 'X\(//\)[^/]' \| \
-        X"$ac_file" : 'X\(//\)$' \| \
-        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-  as_dir="$ac_dir"; as_fn_mkdir_p
-  ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
-  case $ac_mode in
-  :F)
-  #
-  # CONFIG_FILE
-  #
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
-  p
-  q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-  ac_datarootdir_hack='
-  s&@datadir@&$datadir&g
-  s&@docdir@&$docdir&g
-  s&@infodir@&$infodir&g
-  s&@localedir@&$localedir&g
-  s&@mandir@&$mandir&g
-  s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
-  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
-      "$ac_tmp/out"`; test -z "$ac_out"; } &&
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&5
-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&2;}
-
-  rm -f "$ac_tmp/stdin"
-  case $ac_file in
-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
-  esac \
-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-
-
-
-  esac
-
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
-  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded.  So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status.  When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
-  ac_cs_success=:
-  ac_config_status_args=
-  test "$silent" = yes &&
-    ac_config_status_args="$ac_config_status_args --quiet"
-  exec 5>/dev/null
-  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
-  exec 5>>config.log
-  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
-  # would make configure fail if this is the last instruction.
-  $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
-chmod oug+x rtaudio-config
diff --git a/src/rtaudio-mod/configure.ac b/src/rtaudio-mod/configure.ac
deleted file mode 100644 (file)
index fa45967..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-# Process this file with autoconf to produce a configure script.
-AC_INIT(RtAudio, 4.1, gary@music.mcgill.ca, rtaudio)
-AC_CONFIG_AUX_DIR(config)
-AC_CONFIG_SRCDIR(RtAudio.cpp)
-AC_CONFIG_FILES([rtaudio-config librtaudio.pc Makefile tests/Makefile])
-
-# Fill GXX with something before test.
-AC_SUBST( GXX, ["no"] )
-
-dnl Check for pkg-config program, used for configuring some libraries.
-m4_define_default([PKG_PROG_PKG_CONFIG],
-[AC_MSG_CHECKING([pkg-config])
-AC_MSG_RESULT([no])])
-
-PKG_PROG_PKG_CONFIG
-
-dnl If the pkg-config autoconf support isn't installed, define its
-dnl autoconf macro to disable any packages depending on it.
-m4_define_default([PKG_CHECK_MODULES],
-[AC_MSG_CHECKING([$1])
-AC_MSG_RESULT([no])
-$4])
-
-# Checks for programs.
-AC_PROG_CXX(g++ CC c++ cxx)
-AC_PROG_RANLIB
-AC_PATH_PROG(AR, ar, no)
-if [[ $AR = "no" ]] ; then
-    AC_MSG_ERROR("Could not find ar - needed to create a library");
-fi
-
-# Checks for header files.
-AC_HEADER_STDC
-AC_CHECK_HEADERS(sys/ioctl.h unistd.h)
-
-# Check for debug
-AC_MSG_CHECKING(whether to compile debug version)
-AC_ARG_ENABLE(debug,
-  [  --enable-debug = enable various debug output],
-  [AC_SUBST( cppflag, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cxxflag, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)],
-  [AC_SUBST( cppflag, [] ) AC_SUBST( cxxflag, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)])
-
-
-# Checks for functions
-AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], )
-
-# Set paths if prefix is defined
-if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then
-  LIBS="$LIBS -L$prefix/lib"
-  CPPFLAGS="$CPPFLAGS -I$prefix/include"
-fi
-
-# For -I and -D flags
-CPPFLAGS="$CPPFLAGS $cppflag"
-
-# For debugging and optimization ... overwrite default because it has both -g and -O2
-#CXXFLAGS="$CXXFLAGS $cxxflag"
-CXXFLAGS="$cxxflag"
-
-# Check compiler and use -Wall if gnu.
-if [test $GXX = "yes" ;] then
-  AC_SUBST( cxxflag, ["-Wall -Wextra"] )
-fi
-
-CXXFLAGS="$CXXFLAGS $cxxflag"
-
-AC_CANONICAL_HOST
-
-AC_SUBST( sharedlib, ["librtaudio.so"] )
-AC_SUBST( sharedname, ["librtaudio.so.\$(RELEASE)"] )
-AC_SUBST( libflags, ["-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)"] )
-case $host in
-  *-apple*)
-  AC_SUBST( sharedlib, ["librtaudio.dylib"] )
-  AC_SUBST( sharedname, ["librtaudio.\$(RELEASE).dylib"] )
-  AC_SUBST( libflags, ["-dynamiclib -o librtaudio.\$(RELEASE).dylib"] )
-esac
-
-# Checks for package options and external software
-AC_SUBST( api, [""] )
-AC_SUBST( req, [""] )
-AC_MSG_CHECKING(for audio API)
-case $host in
-  *-*-netbsd*)
-    AC_MSG_RESULT(using OSS)
-    api="$api -D__LINUX_OSS__"
-    LIBS="$LIBS -lossaudio"
-    AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
-  ;;
-
-  *-*-linux*)
-  AC_ARG_WITH(jack, [  --with-jack = choose JACK server support (mac and linux only)], [
-    api="$api -D__UNIX_JACK__"
-    AC_MSG_RESULT(using JACK)
-    AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))
-    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))], )
-
-  # Look for ALSA flag
-  AC_ARG_WITH(alsa, [  --with-alsa = choose native ALSA API support (linux only)], [
-    api="$api -D__LINUX_ALSA__"
-    req="$req alsa"
-    AC_MSG_RESULT(using ALSA)
-    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], )
-
-  # Look for PULSE flag
-  AC_ARG_WITH(pulse, [  --with-pulse = choose PulseAudio API support (linux only)], [
-    api="$api -D__LINUX_PULSE__"
-    req="$req libpulse-simple"
-    AC_MSG_RESULT(using PulseAudio)
-    PKG_CHECK_MODULES([PULSE], [libpulse-simple], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))
-        LIBS="$LIBS `pkg-config --libs libpulse-simple`" ], )
-
-  # Look for OSS flag
-  AC_ARG_WITH(oss, [  --with-oss = choose OSS API support (linux only)], [
-    api="$api -D__LINUX_OSS__"
-    AC_MSG_RESULT(using OSS)], )
-
-  # If no audio api flags specified, use ALSA
-  if [test "$api" == "";] then
-    AC_MSG_RESULT(using ALSA)
-    AC_SUBST( api, [-D__LINUX_ALSA__] )
-    req="$req alsa"
-    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
-  fi
-
-  AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
-  ;;
-
-  *-apple*)
-  AC_ARG_WITH(jack, [  --with-jack = choose JACK server support (unix only)], [
-    api="$api -D__UNIX_JACK__"
-    AC_MSG_RESULT(using JACK)
-    AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))], )
-
-#    AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] )
-#    LIBS="$LIBS -framework jackmp" ], )
-
-
-  # Look for Core flag
-  AC_ARG_WITH(core, [  --with-core = choose CoreAudio API support (mac only)], [
-    api="$api -D__MACOSX_CORE__"
-    AC_MSG_RESULT(using CoreAudio)
-    AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] )
-    LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ], )
-
-  # If no audio api flags specified, use CoreAudio
-  if [test "$api" == ""; ] then
-    AC_SUBST( api, [-D__MACOSX_CORE__] )
-    AC_MSG_RESULT(using CoreAudio)
-    AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
-      [],
-      [AC_MSG_ERROR(CoreAudio header files not found!)] )
-    AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] )
-  fi
-
-  AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
-  ;;
-
-  *-mingw32*)
-  AC_ARG_WITH(asio, [  --with-asio = choose ASIO API support (windoze only)], [
-    api="$api -D__WINDOWS_ASIO__"
-    AC_MSG_RESULT(using ASIO)
-    AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ], )
-
-  # Look for DirectSound flag
-  AC_ARG_WITH(ds, [  --with-ds = choose DirectSound API support (windoze only)], [
-    api="$api -D__WINDOWS_DS__"
-    AC_MSG_RESULT(using DirectSound)
-    LIBS="-ldsound -lwinmm $LIBS" ], )
-
-  # Look for WASAPI flag
-  AC_ARG_WITH(wasapi, [  --with-wasapi = choose Windows Audio Session API support (windoze only)], [
-    api="$api -D__WINDOWS_WASAPI__"
-    AC_MSG_RESULT(using WASAPI)
-    LIBS="-lwinmm -luuid -lksuser $LIBS" ], )
-
-  # If no audio api flags specified, use DS
-  if [test "$api" == "";] then
-    AC_SUBST( api, [-D__WINDOWS_DS__] )
-    AC_MSG_RESULT(using DirectSound)
-    LIBS="-ldsound -lwinmm $LIBS"
-  fi
-
-  LIBS="-lole32 $LIBS"
-  ;;
-
-  *)
-  # Default case for unknown realtime systems.
-  AC_MSG_ERROR(Unknown system type for realtime support!)
-  ;;
-esac
-
-CPPFLAGS="$CPPFLAGS $api"
-
-AC_OUTPUT
-
-chmod oug+x rtaudio-config
diff --git a/src/rtaudio-mod/librtaudio.pc.in b/src/rtaudio-mod/librtaudio.pc.in
deleted file mode 100644 (file)
index 45c3f4e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=${prefix}
-libdir=${exec_prefix}/lib
-includedir=${prefix}/include        
-
-Name: librtaudio
-Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output
-Version: 4.1.1
-Requires: @req@ 
-Libs: -L${libdir} -lrtaudio
-Libs.private: -lpthread
-Cflags: -pthread -I${includedir} @CPPFLAGS@
\ No newline at end of file
diff --git a/src/rtaudio-mod/rtaudio-config.in b/src/rtaudio-mod/rtaudio-config.in
deleted file mode 100644 (file)
index 5f83d51..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#! /bin/sh
-if (test "x$#" != "x1") ; then
-  echo "Usage: $0 [--libs | --cxxflags | --cppflags]"
-  exit;
-fi
-
-LIBRARY="@LIBS@"
-CXXFLAGS="@CXXFLAGS@"
-CPPFLAGS="@CPPFLAGS@"
-
-if (test "x$1" = "x--libs") ; then
-  echo "$LIBRARY -lrtaudio"
-elif (test "x$1" = "x--cxxflags") ; then
-  echo "$CXXFLAGS"
-elif (test "x$1" = "x--cppflags") ; then
-  echo "$CPPFLAGS"
-else
-  echo "Unknown option: $1"
-fi
diff --git a/src/sampleChannel.cpp b/src/sampleChannel.cpp
deleted file mode 100644 (file)
index 1b9cb29..0000000
+++ /dev/null
@@ -1,1036 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <math.h>
-#include "sampleChannel.h"
-#include "patch.h"
-#include "conf.h"
-#include "wave.h"
-#include "pluginHost.h"
-#include "waveFx.h"
-#include "mixerHandler.h"
-#include "kernelMidi.h"
-#include "log.h"
-
-
-extern Patch       G_Patch;
-extern Mixer       G_Mixer;
-extern Conf        G_Conf;
-#ifdef WITH_VST
-extern PluginHost  G_PluginHost;
-#endif
-
-
-SampleChannel::SampleChannel(int bufferSize)
-       : Channel          (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize),
-               frameRewind      (-1),
-               wave             (NULL),
-               tracker          (0),
-               begin            (0),
-               end              (0),
-               pitch            (gDEFAULT_PITCH),
-               boost            (1.0f),
-               mode             (DEFAULT_CHANMODE),
-               qWait              (false),
-               fadeinOn         (false),
-               fadeinVol        (1.0f),
-               fadeoutOn        (false),
-               fadeoutVol       (1.0f),
-               fadeoutTracker   (0),
-               fadeoutStep      (DEFAULT_FADEOUT_STEP),
-         readActions      (true),
-         midiInReadActions(0x0),
-         midiInPitch      (0x0)
-{
-       rsmp_state = src_new(SRC_LINEAR, 2, NULL);
-       pChan      = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-SampleChannel::~SampleChannel()
-{
-       if (wave)
-               delete wave;
-       src_delete(rsmp_state);
-       free(pChan);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::clear()
-{
-       /** TODO - these memsets can be done only if status PLAY (if below),
-        * but it would require extra clearPChan calls when samples stop */
-
-               memset(vChan, 0, sizeof(float) * bufferSize);
-               memset(pChan, 0, sizeof(float) * bufferSize);
-
-       if (status & (STATUS_PLAY | STATUS_ENDING)) {
-               tracker = fillChan(vChan, tracker, 0);
-               if (fadeoutOn && fadeoutType == XFADE) {
-                       gLog("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker);
-                       fadeoutTracker = fillChan(pChan, fadeoutTracker, 0);
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::calcVolumeEnv(int frame)
-{
-       /* method: check this frame && next frame, then calculate delta */
-
-       recorder::action *a0 = NULL;
-       recorder::action *a1 = NULL;
-       int res;
-
-       /* get this action on frame 'frame'. It's unlikely that the action
-        * is not found. */
-
-       res = recorder::getAction(index, ACTION_VOLUME, frame, &a0);
-       if (res == 0)
-               return;
-
-       /* get the action next to this one.
-        * res == -1: a1 not found, this is the last one. Rewind the search
-        * and use action at frame number 0 (actions[0]).
-        * res == -2 ACTION_VOLUME not found. This should never happen */
-
-       res = recorder::getNextAction(index, ACTION_VOLUME, frame, &a1);
-
-       if (res == -1)
-               res = recorder::getAction(index, ACTION_VOLUME, 0, &a1);
-
-       volume_i = a0->fValue;
-       volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::hardStop(int frame)
-{
-       if (frame != 0)        // clear data in range [frame, bufferSize-1]
-               clearChan(vChan, frame);
-       status = STATUS_OFF;
-       sendMidiLplay();
-       reset(frame);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::onBar(int frame)
-{
-       ///if (mode == LOOP_REPEAT && status == STATUS_PLAY)
-       ///     //setXFade(frame);
-       ///     reset(frame);
-
-       if (mode == LOOP_REPEAT) {
-               if (status == STATUS_PLAY)
-                       //setXFade(frame);
-                       reset(frame);
-       }
-       else
-       if (mode == LOOP_ONCE_BAR) {
-               if (status == STATUS_WAIT) {
-                       status  = STATUS_PLAY;
-                       tracker = fillChan(vChan, tracker, frame);
-                       sendMidiLplay();
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::save(const char *path)
-{
-       return wave->writeData(path);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setBegin(unsigned v)
-{
-       begin   = v;
-       tracker = begin;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setEnd(unsigned v)
-{
-       end = v;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setPitch(float v)
-{
-       pitch = v;
-       rsmp_data.src_ratio = 1/pitch;
-
-       /* if status is off don't slide between frequencies */
-
-       if (status & (STATUS_OFF | STATUS_WAIT))
-               src_set_ratio(rsmp_state, 1/pitch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::rewind()
-{
-       /* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */
-
-       if (wave != NULL) {
-               if ((mode & LOOP_ANY) || (recStatus == REC_READING && (mode & SINGLE_ANY)))
-                       reset(0);  // rewind is user-generated events, always on frame 0
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
-{
-       if (readActions == false)
-               return;
-
-       switch (a->type) {
-               case ACTION_KEYPRESS:
-                       if (mode & SINGLE_ANY)
-                               start(localFrame, false);
-                       break;
-               case ACTION_KEYREL:
-                       if (mode & SINGLE_ANY)
-                               stop();
-                       break;
-               case ACTION_KILLCHAN:
-                       if (mode & SINGLE_ANY)
-                               kill(localFrame);
-                       break;
-               case ACTION_MUTEON:
-                       setMute(true);   // internal mute
-                       break;
-               case ACTION_MUTEOFF:
-                       unsetMute(true); // internal mute
-                       break;
-               case ACTION_VOLUME:
-                       calcVolumeEnv(globalFrame);
-                       break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::sum(int frame, bool running)
-{
-       if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING))
-               return;
-
-       if (frame != frameRewind) {
-
-               /* volume envelope, only if seq is running */
-
-               if (running) {
-                       volume_i += volume_d;
-                       if (volume_i < 0.0f)
-                               volume_i = 0.0f;
-                       else
-                       if (volume_i > 1.0f)
-                               volume_i = 1.0f;
-               }
-
-               /* fadein or fadeout processes. If mute, delete any signal. */
-
-               /** TODO - big issue: fade[in/out]Vol * internal_volume might be a
-                * bad choice: it causes glitches when muting on and off during a
-                * volume envelope. */
-
-               if (mute || mute_i) {
-                       vChan[frame]   = 0.0f;
-                       vChan[frame+1] = 0.0f;
-               }
-               else
-               if (fadeinOn) {
-                       if (fadeinVol < 1.0f) {
-                               vChan[frame]   *= fadeinVol * volume_i;
-                               vChan[frame+1] *= fadeinVol * volume_i;
-                               fadeinVol += 0.01f;
-                       }
-                       else {
-                               fadeinOn  = false;
-                               fadeinVol = 0.0f;
-                       }
-               }
-               else
-               if (fadeoutOn) {
-                       if (fadeoutVol > 0.0f) { // fadeout ongoing
-                               if (fadeoutType == XFADE) {
-                                       vChan[frame]   *= volume_i;
-                                       vChan[frame+1] *= volume_i;
-                                       vChan[frame]    = pChan[frame]   * fadeoutVol * volume_i;
-                                       vChan[frame+1]  = pChan[frame+1] * fadeoutVol * volume_i;
-                               }
-                               else {
-                                       vChan[frame]   *= fadeoutVol * volume_i;
-                                       vChan[frame+1] *= fadeoutVol * volume_i;
-                               }
-                               fadeoutVol -= fadeoutStep;
-                       }
-                       else {  // fadeout end
-                               fadeoutOn  = false;
-                               fadeoutVol = 1.0f;
-
-                               /* QWait ends with the end of the xfade */
-
-                               if (fadeoutType == XFADE) {
-                                       qWait = false;
-                               }
-                               else {
-                                       if (fadeoutEnd == DO_MUTE)
-                                               mute = true;
-                                       else
-                                       if (fadeoutEnd == DO_MUTE_I)
-                                               mute_i = true;
-                                       else             // DO_STOP
-                                               hardStop(frame);
-                               }
-                       }
-               }
-               else {
-                       vChan[frame]   *= volume_i;
-                       vChan[frame+1] *= volume_i;
-               }
-       }
-       else {
-
-               if (mode & (SINGLE_BASIC | SINGLE_PRESS | SINGLE_RETRIG) ||
-                        (mode == SINGLE_ENDLESS && status == STATUS_ENDING)   ||
-                        (mode & LOOP_ANY && !running))     // stop loops when the seq is off
-               {
-                       status = STATUS_OFF;
-                       sendMidiLplay();
-               }
-
-               /* temporary stop LOOP_ONCE not in ENDING status, otherwise they
-                * would return in wait, losing the ENDING status */
-
-               //if (mode == LOOP_ONCE && status != STATUS_ENDING)
-               if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING) {
-                       status = STATUS_WAIT;
-                       sendMidiLplay();
-               }
-
-               /* check for end of samples. SINGLE_ENDLESS runs forever unless
-                * it's in ENDING mode. */
-
-               reset(frame);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::onZero(int frame)
-{
-       if (wave == NULL)
-               return;
-
-       if (mode & LOOP_ANY) {
-
-               /* do a crossfade if the sample is playing. Regular chanReset
-                * instead if it's muted, otherwise a click occurs */
-
-               if (status == STATUS_PLAY) {
-                       /*
-                       if (mute || mute_i)
-                               reset(frame);
-                       else
-                               setXFade(frame);
-                       */
-                       reset(frame);
-               }
-               else
-               if (status == STATUS_ENDING)
-                       hardStop(frame);
-       }
-
-       if (status == STATUS_WAIT) { /// FIXME - should be inside previous if!
-               status  = STATUS_PLAY;
-               sendMidiLplay();
-               tracker = fillChan(vChan, tracker, frame);
-       }
-
-       if (recStatus == REC_ENDING) {
-               recStatus = REC_STOPPED;
-               setReadActions(false);  // rec stop
-       }
-       else
-       if (recStatus == REC_WAITING) {
-               recStatus = REC_READING;
-               setReadActions(true);   // rec start
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::quantize(int index, int localFrame, int globalFrame)
-{
-       /* skip if LOOP_ANY or not in quantizer-wait mode */
-
-       if ((mode & LOOP_ANY) || !qWait)
-               return;
-
-       /* no fadeout if the sample starts for the first time (from a
-        * STATUS_OFF), it would be meaningless. */
-
-       if (status == STATUS_OFF) {
-               status  = STATUS_PLAY;
-               sendMidiLplay();
-               qWait   = false;
-               tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ???
-       }
-       else
-               //setXFade(localFrame);
-               reset(localFrame);
-
-       /* this is the moment in which we record the keypress, if the
-        * quantizer is on. SINGLE_PRESS needs overdub */
-
-       if (recorder::canRec(this)) {
-               if (mode == SINGLE_PRESS)
-                       recorder::startOverdub(index, ACTION_KEYS, globalFrame);
-               else
-                       recorder::rec(index, ACTION_KEYPRESS, globalFrame);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::getPosition()
-{
-       if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...)
-               return tracker - begin;
-       else
-               return -1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setMute(bool internal)
-{
-       if (internal) {
-
-               /* global mute is on? don't waste time with fadeout, just mute it
-                * internally */
-
-               if (mute)
-                       mute_i = true;
-               else {
-                       if (isPlaying())
-                               setFadeOut(DO_MUTE_I);
-                       else
-                               mute_i = true;
-               }
-       }
-       else {
-
-               /* internal mute is on? don't waste time with fadeout, just mute it
-                * globally */
-
-               if (mute_i)
-                       mute = true;
-               else {
-
-                       /* sample in play? fadeout needed. Else, just mute it globally */
-
-                       if (isPlaying())
-                               setFadeOut(DO_MUTE);
-                       else
-                               mute = true;
-               }
-       }
-
-       sendMidiLmute();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::unsetMute(bool internal)
-{
-       if (internal) {
-               if (mute)
-                       mute_i = false;
-               else {
-                       if (isPlaying())
-                               setFadeIn(internal);
-                       else
-                               mute_i = false;
-               }
-       }
-       else {
-               if (mute_i)
-                       mute = false;
-               else {
-                       if (isPlaying())
-                               setFadeIn(internal);
-                       else
-                               mute = false;
-               }
-       }
-
-       sendMidiLmute();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::calcFadeoutStep()
-{
-       if (end - tracker < (1 / DEFAULT_FADEOUT_STEP) * 2)
-               fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ???
-       else
-               fadeoutStep = DEFAULT_FADEOUT_STEP;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setReadActions(bool v)
-{
-       if (v)
-               readActions = true;
-       else {
-               readActions = false;
-               if (G_Conf.recsStopOnChanHalt)
-                       kill(0);  /// FIXME - wrong frame value
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setFadeIn(bool internal)
-{
-       if (internal) mute_i = false;  // remove mute before fading in
-       else          mute   = false;
-       fadeinOn  = true;
-       fadeinVol = 0.0f;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setFadeOut(int actionPostFadeout)
-{
-       calcFadeoutStep();
-       fadeoutOn   = true;
-       fadeoutVol  = 1.0f;
-       fadeoutType = FADEOUT;
-       fadeoutEnd      = actionPostFadeout;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setXFade(int frame)
-{
-       gLog("[xFade] frame=%d tracker=%d\n", frame, tracker);
-
-       calcFadeoutStep();
-       fadeoutOn      = true;
-       fadeoutVol     = 1.0f;
-       fadeoutType    = XFADE;
-       fadeoutTracker = fillChan(pChan, tracker, 0, false);
-       reset(frame);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* on reset, if frame > 0 and in play, fill again pChan to create
- * something like this:
- *
- * |abcdefabcdefab*abcdefabcde|
- * [old data-----]*[new data--]
- *
- * */
-
-void SampleChannel::reset(int frame)
-{
-       //fadeoutTracker = tracker;   // store old frame number for xfade
-       tracker = begin;
-       mute_i  = false;
-       if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING))
-               tracker = fillChan(vChan, tracker, frame);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::empty()
-{
-       status = STATUS_OFF;
-       if (wave) {
-               delete wave;
-               wave = NULL;
-       }
-       status = STATUS_EMPTY;
-       sendMidiLplay();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::pushWave(Wave *w)
-{
-       wave   = w;
-       status = STATUS_OFF;
-       sendMidiLplay();
-       begin  = 0;
-       end    = wave->size;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool SampleChannel::allocEmpty(int frames, int takeId)
-{
-       Wave *w = new Wave();
-       if (!w->allocEmpty(frames))
-               return false;
-
-       char wname[32];
-       sprintf(wname, "TAKE-%d", takeId);
-
-       w->pathfile = gGetCurrentPath()+"/"+wname; // FIXME - use gGetSlash() in utils.h
-       w->name     = wname;
-       wave        = w;
-       status      = STATUS_OFF;
-       begin       = 0;
-       end         = wave->size;
-
-       sendMidiLplay();
-
-       return true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::process(float *buffer)
-{
-#ifdef WITH_VST
-       G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
-#endif
-
-       for (int j=0; j<bufferSize; j+=2) {
-               buffer[j]   += vChan[j]   * volume * panLeft  * boost;
-               buffer[j+1] += vChan[j+1] * volume * panRight * boost;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::kill(int frame)
-{
-       if (wave != NULL && status != STATUS_OFF) {
-               if (mute || mute_i || (status == STATUS_WAIT && mode & LOOP_ANY))
-                       hardStop(frame);
-               else
-                       setFadeOut(DO_STOP);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::stopBySeq()
-{
-       /* kill loop channels and recs if "samplesStopOnSeqHalt" == true,
-        * else do nothing and return. Always kill at frame=0, this is a
-        * user-generated event. */
-
-       if (!G_Conf.chansStopOnSeqHalt)
-               return;
-
-       if (mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT))
-               kill(0);
-
-       /** FIXME - merge these */
-
-       /* when a channel has recs in play?
-        * Recorder has events for that channel
-        * G_Mixer has at least one sample in play
-        * Recorder's channel is active (altrimenti può capitare che
-        * si stoppino i sample suonati manualmente in un canale con rec
-        * disattivate) */
-
-       if (hasActions && readActions && status == STATUS_PLAY)
-               kill(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::stop()
-{
-       if (mode == SINGLE_PRESS && status == STATUS_PLAY) {
-               if (mute || mute_i)
-                       hardStop(0);  /// FIXME - wrong frame value
-               else
-                       setFadeOut(DO_STOP);
-       }
-       else  // stop a SINGLE_PRESS immediately, if the quantizer is on
-       if (mode == SINGLE_PRESS && qWait == true)
-               qWait = false;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::load(const char *file)
-{
-       if (strcmp(file, "") == 0 || gIsDir(file)) {
-               gLog("[SampleChannel] file not specified\n");
-               return SAMPLE_LEFT_EMPTY;
-       }
-
-       if (strlen(file) > FILENAME_MAX)
-               return SAMPLE_PATH_TOO_LONG;
-
-       Wave *w = new Wave();
-
-       if (!w->open(file)) {
-               gLog("[SampleChannel] %s: read error\n", file);
-               delete w;
-               return SAMPLE_READ_ERROR;
-       }
-
-       if (w->channels() > 2) {
-               gLog("[SampleChannel] %s: unsupported multichannel wave\n", file);
-               delete w;
-               return SAMPLE_MULTICHANNEL;
-       }
-
-       if (!w->readData()) {
-               delete w;
-               return SAMPLE_READ_ERROR;
-       }
-
-       if (w->channels() == 1) /** FIXME: error checking  */
-               wfx_monoToStereo(w);
-
-       if (w->rate() != G_Conf.samplerate) {
-               gLog("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n",
-                               w->rate(), G_Conf.samplerate);
-               w->resample(G_Conf.rsmpQuality, G_Conf.samplerate);
-       }
-
-       pushWave(w);
-
-       /* sample name must be unique. Start from k = 1, zero is too nerdy */
-
-       std::string oldName = wave->name;
-       int k = 1;
-       while (!mh_uniqueSamplename(this, wave->name.c_str())) {
-               wave->updateName((oldName + "-" + gItoa(k)).c_str());
-               k++;
-       }
-
-       gLog("[SampleChannel] %s loaded in channel %d\n", file, index);
-       return SAMPLE_LOADED_OK;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::loadByPatch(const char *f, int i)
-{
-       int res = load(f);
-
-               volume      = G_Patch.getVol(i);
-               key         = G_Patch.getKey(i);
-               index       = G_Patch.getIndex(i);
-               mode        = G_Patch.getMode(i);
-               mute        = G_Patch.getMute(i);
-               mute_s      = G_Patch.getMute_s(i);
-               solo        = G_Patch.getSolo(i);
-               boost       = G_Patch.getBoost(i);
-               panLeft     = G_Patch.getPanLeft(i);
-               panRight    = G_Patch.getPanRight(i);
-               readActions = G_Patch.getRecActive(i);
-               recStatus   = readActions ? REC_READING : REC_STOPPED;
-
-               readPatchMidiIn(i);
-               midiInReadActions = G_Patch.getMidiValue(i, "InReadActions");
-               midiInPitch       = G_Patch.getMidiValue(i, "InPitch");
-               readPatchMidiOut(i);
-
-       if (res == SAMPLE_LOADED_OK) {
-               setBegin(G_Patch.getBegin(i));
-               setEnd  (G_Patch.getEnd(i, wave->size));
-               setPitch(G_Patch.getPitch(i));
-       }
-       else {
-               // volume = DEFAULT_VOL;
-               // mode   = DEFAULT_CHANMODE;
-               // status = STATUS_WRONG;
-               // key    = 0;
-
-               if (res == SAMPLE_LEFT_EMPTY)
-                       status = STATUS_EMPTY;
-               else
-               if (res == SAMPLE_READ_ERROR)
-                       status = STATUS_MISSING;
-               sendMidiLplay();
-       }
-
-       return res;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool SampleChannel::canInputRec()
-       {
-       return wave == NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::start(int frame, bool doQuantize)
-{
-       switch (status) {
-               case STATUS_EMPTY:
-               case STATUS_MISSING:
-               case STATUS_WRONG:
-               {
-                       return;
-               }
-
-               case STATUS_OFF:
-               {
-                       if (mode & LOOP_ANY) {
-                               status = STATUS_WAIT;
-                               sendMidiLplay();
-                       }
-                       else {
-                               if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
-                                       qWait = true;
-                               else {
-
-                                       /* fillChan only if frame != 0. If you call fillChan on frame == 0
-                                        * a duplicate call to fillChan occurs with loss of data. */
-
-                                       status = STATUS_PLAY;
-                                       sendMidiLplay();
-                                       if (frame != 0)
-                                               tracker = fillChan(vChan, tracker, frame);
-                               }
-                       }
-                       break;
-               }
-
-               case STATUS_PLAY:
-               {
-                       if (mode == SINGLE_BASIC)
-                               setFadeOut(DO_STOP);
-                       else
-                       if (mode == SINGLE_RETRIG) {
-                               if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
-                                       qWait = true;
-                               else
-                                       reset(frame);
-                       }
-                       else
-                       if (mode & (LOOP_ANY | SINGLE_ENDLESS)) {
-                               status = STATUS_ENDING;
-                               sendMidiLplay();
-                       }
-                       break;
-               }
-
-               case STATUS_WAIT:
-               {
-                       status = STATUS_OFF;
-                       sendMidiLplay();
-                       break;
-               }
-
-               case STATUS_ENDING:
-               {
-                       status = STATUS_PLAY;
-                       sendMidiLplay();
-                       break;
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::writePatch(FILE *fp, int i, bool isProject)
-{
-       Channel::writePatch(fp, i, isProject);
-
-       const char *path = "";
-       if (wave != NULL) {
-               path = wave->pathfile.c_str();
-               if (isProject)
-                       path = gBasename(path).c_str();  // make it portable
-       }
-
-       fprintf(fp, "samplepath%d=%s\n",     i, path);
-       fprintf(fp, "chanKey%d=%d\n",        i, key);
-       //fprintf(fp, "columnIndex%d=%d\n",    i, index);
-       fprintf(fp, "chanmode%d=%d\n",       i, mode);
-       fprintf(fp, "chanBegin%d=%d\n",      i, begin);
-       fprintf(fp, "chanend%d=%d\n",        i, end);
-       fprintf(fp, "chanBoost%d=%f\n",      i, boost);
-       fprintf(fp, "chanRecActive%d=%d\n",  i, readActions);
-       fprintf(fp, "chanPitch%d=%f\n",      i, pitch);
-
-       fprintf(fp, "chanMidiInReadActions%d=%u\n", i, midiInReadActions);
-       fprintf(fp, "chanMidiInPitch%d=%u\n",       i, midiInPitch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::clearChan(float *dest, int start)
-{
-       memset(dest+start, 0, sizeof(float)*(bufferSize-start));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind)
-{
-       int position;  // return value: the new position
-
-       if (pitch == 1.0f) {
-
-               /* case 1: 'dest' lies within the original sample boundaries (start-
-                * end) */
-
-               if (start+bufferSize-offset <= end) {
-                       memcpy(dest+offset, wave->data+start, (bufferSize-offset)*sizeof(float));
-                       position = start+bufferSize-offset;
-                       if (rewind)
-                               frameRewind = -1;
-               }
-
-               /* case2: 'dest' lies outside the end of the sample, OR the sample
-                * is smaller than 'dest' */
-
-               else {
-                       memcpy(dest+offset, wave->data+start, (end-start)*sizeof(float));
-                       position = end;
-                       if (rewind)
-                               frameRewind = end-start+offset;
-               }
-       }
-       else {
-
-               rsmp_data.data_in       = wave->data+start;         // source data
-               rsmp_data.input_frames  = (end-start)/2;            // how many readable bytes
-               rsmp_data.data_out      = dest+offset;              // destination (processed data)
-               rsmp_data.output_frames = (bufferSize-offset)/2;    // how many bytes to process
-               rsmp_data.end_of_input  = false;
-
-               src_process(rsmp_state, &rsmp_data);
-               int gen = rsmp_data.output_frames_gen*2;            // frames generated by this call
-
-               position = start + rsmp_data.input_frames_used*2;   // position goes forward of frames_used (i.e. read from wave)
-
-               if (rewind) {
-                       if (gen == bufferSize-offset)
-                               frameRewind = -1;
-                       else
-                               frameRewind = gen+offset;
-               }
-       }
-       return position;
-}
diff --git a/src/sampleChannel.h b/src/sampleChannel.h
deleted file mode 100644 (file)
index 736063a..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * sampleChannel
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef SAMPLE_CHANNEL_H
-#define SAMPLE_CHANNEL_H
-
-
-#include <samplerate.h>
-#include "channel.h"
-
-
-class SampleChannel : public Channel {
-
-private:
-
-       /* rsmp_state, rsmp_data
-        * structs from libsamplerate */
-
-       SRC_STATE *rsmp_state;
-       SRC_DATA   rsmp_data;
-
-       /* pChan
-        * extra virtual channel for processing resampled data.  */
-
-       float *pChan;
-
-       /* frameRewind
-        * exact frame in which a rewind occurs */
-
-       int frameRewind;
-
-       /* fillChan
-        * copy from wave to *dest and resample data from wave, if necessary.
-        * Start to fill pChan from byte 'offset'. If rewind=false don't
-        * rewind internal tracker. Returns new sample position, in frames */
-
-       int fillChan(float *dest, int start, int offset, bool rewind=true);
-
-       /* clearChan
-        * set data to zero from start to bufferSize-1. */
-
-       void clearChan(float *dest, int start);
-
-       /* calcFadeoutStep
-        * how many frames are left before the end of the sample? Is there
-        * enough room for a complete fadeout? Should we shorten it? */
-
-       void calcFadeoutStep();
-
-       /* calcVolumeEnv
-        * compute any changes in volume done via envelope tool */
-
-       void calcVolumeEnv(int frame);
-
-public:
-
-       SampleChannel(int bufferSize);
-       ~SampleChannel();
-
-       void  clear      ();
-       void  process    (float *buffer);
-       void  start      (int frame, bool doQuantize);
-       void  kill       (int frame);
-       void  empty      ();
-       void  stopBySeq  ();
-       void  stop       ();
-       void  rewind     ();
-       void  setMute    (bool internal);
-       void  unsetMute  (bool internal);
-       void  reset      (int frame);
-       int   load       (const char *file);
-       int   loadByPatch(const char *file, int i);
-       void  writePatch (FILE *fp, int i, bool isProject);
-       void  quantize   (int index, int localFrame, int globalFrame);
-       void  onZero     (int frame);
-       void  onBar      (int frame);
-       void  parseAction(recorder::action *a, int localFrame, int globalFrame);
-
-       /* fade methods
-        * prepare channel for fade, mixer will take care of the process
-        * during master play. */
-
-       void  setFadeIn  (bool internal);
-       void  setFadeOut (int actionPostFadeout);
-       void  setXFade   (int frame);
-
-       /* pushWave
-        * add a new wave to an existing channel. */
-
-       void pushWave(class Wave *w);
-
-       /* getPosition
-        * returns the position of an active sample. If EMPTY o MISSING
-        * returns -1. */
-
-       int getPosition();
-
-       /* sum
-        * add sample frames to virtual channel. Frame = processed frame in
-        * Mixer. Running = is Mixer in play? */
-
-       void sum(int frame, bool running);
-
-       /* setPitch
-        * updates the pitch value and chanStart+chanEnd accordingly. */
-
-       void setPitch(float v);
-
-       /* setStart/end
-        * change begin/end read points in sample. */
-
-       void setBegin(unsigned v);
-       void setEnd  (unsigned v);
-
-       /* save
-        * save sample to file. */
-
-       int save(const char *path);
-
-       /* hardStop
-        * stop the channel immediately, no further checks. */
-
-       void hardStop(int frame);
-
-       /* allocEmpty
-        * alloc an empty wave used in input recordings. */
-
-       bool allocEmpty(int frames, int takeId);
-
-       /* canInputRec
-        * true if channel can host a new wave from input recording. */
-
-       bool  canInputRec();
-
-       /* setReadActions
-        * if enabled, recorder will read actions from this channel */
-
-       void setReadActions(bool v);
-
-       /* ---------------------------------------------------------------- */
-
-       class  Wave *wave;
-       int    tracker;         // chan position
-       int    begin;
-       int    end;
-  float  pitch;
-       float  boost;
-       int    mode;            // mode: see const.h
-       bool   qWait;           // quantizer wait
-       bool   fadeinOn;
-       float  fadeinVol;
-       bool   fadeoutOn;
-       float  fadeoutVol;      // fadeout volume
-       int    fadeoutTracker;  // tracker fadeout, xfade only
-       float  fadeoutStep;     // fadeout decrease
-  int    fadeoutType;     // xfade or fadeout
-  int           fadeoutEnd;      // what to do when fadeout ends
-
-       /* recorder:: stuff */
-
-  bool   readActions;     // read actions or not
-
-       /* midi stuff */
-
-  uint32_t midiInReadActions;
-  uint32_t midiInPitch;
-
-       /* const - what to do when a fadeout ends */
-
-       enum {
-               DO_STOP   = 0x01,
-               DO_MUTE   = 0x02,
-               DO_MUTE_I = 0x04
-       };
-
-       /*  const - fade types */
-
-       enum {
-               FADEOUT = 0x01,
-               XFADE   = 0x02
-       };
-};
-
-#endif
diff --git a/src/utils.cpp b/src/utils.cpp
deleted file mode 100644 (file)
index e7b2e8c..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "utils.h"
-#if defined(_WIN32)                    // getcwd (unix) or __getcwd (win)
-       #include <direct.h>
-       #include <windows.h>
-#else
-       #include <unistd.h>
-#endif
-
-#include <cstdarg>
-#include <sys/stat.h>   // stat (gDirExists)
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string>
-#include <string.h>
-#include <sstream>
-#include <limits.h>
-#if defined(__APPLE__)
-       #include <libgen.h>     // basename unix
-       #include <pwd.h>        // getpwuid
-#endif
-
-
-
-bool gFileExists(const char *filename) {
-       FILE *fh = fopen(filename, "rb");
-       if (!fh) {
-               return 0;
-       }
-       else {
-               fclose(fh);
-               return 1;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsDir(const char *path)
-{
-       bool ret;
-
-#if defined(__linux__)
-
-       struct stat s1;
-       stat(path, &s1);
-       ret = S_ISDIR(s1.st_mode);
-
-#elif defined(__APPLE__)
-
-       if (strcmp(path, "")==0)
-               ret = false;
-       else {
-               struct stat s1;
-               stat(path, &s1);
-               ret = S_ISDIR(s1.st_mode);
-
-               /* check if ret is a bundle, a special OS X folder which must be
-                * shown as a regular file (VST).
-                * FIXME - consider native functions CFBundle... */
-
-               if (ret) {
-                       std::string tmp = path;
-                       tmp += "/Contents/Info.plist";
-                       if (gFileExists(tmp.c_str()))
-                               ret = false;
-               }
-       }
-
-#elif defined(__WIN32)
-
-  unsigned dwAttrib = GetFileAttributes(path);
-  ret = (dwAttrib != INVALID_FILE_ATTRIBUTES &&
-        (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
-#endif
-
-       return ret & !gIsProject(path);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gDirExists(const char *path)
-{
-       struct stat st;
-       if (stat(path, &st) != 0 && errno == ENOENT)
-               return false;
-       return true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gMkdir(const char *path)
-{
-#if defined(__linux__) || defined(__APPLE__)
-       if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
-#else
-       if (_mkdir(path) == 0)
-#endif
-               return true;
-       return false;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gBasename(const char *path)
-{
-       std::string out = path;
-       out.erase(0, out.find_last_of(gGetSlash().c_str())+1);
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gDirname(const char *path)
-{
-       std::string out = path;
-       out.erase(out.find_last_of(gGetSlash().c_str()));
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gGetCurrentPath()
-{
- char buf[PATH_MAX];
-#if defined(__WIN32)
-       if (_getcwd(buf, PATH_MAX) != NULL)
-#else
-       if (getcwd(buf, PATH_MAX) != NULL)
-#endif
-               return buf;
-       else
-               return "";
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gGetExt(const char *file)
-{
-       int len = strlen(file);
-       int pos = len;
-       while (pos>0) {
-               if (file[pos] == '.')
-                       break;
-               pos--;
-       }
-       if (pos==0)
-               return "";
-       std::string out = file;
-       return out.substr(pos+1, len);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gStripExt(const char *file)
-{
-       int len = strlen(file);
-       int pos = -1;
-       for (int i=0; i<len; i++)
-               if (file[i] == '.') {
-                       pos = i;
-                       break;
-               }
-       std::string out = file;
-       return pos == -1 ? out : out.substr(0, pos);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsProject(const char *path)
-{
-       /** FIXME - checks too weak */
-
-       if (gGetExt(path) == "gprj" && gDirExists(path))
-               return 1;
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsPatch(const char *path)
-{
-       if (gGetExt(path) == "gptc")
-               return 1;
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gGetProjectName(const char *path)
-{
-       std::string out;
-       out = gStripExt(path);
-
-       int i = out.size();
-       while (i>=0) { /// TODO - use gGetSlash()
-#if defined(__linux__) || defined(__APPLE__)
-               if (out[i] == '/')
-#elif defined(_WIN32)
-               if (out[i] == '\\')
-#endif
-                       break;
-               i--;
-       }
-
-       out.erase(0, i+1);      // includes the '/' (or '\' on windows)
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gGetSlash() // TODO - create SLASH macro or constant
-{
-#if defined(_WIN32)
-       return "\\";
-#else
-       return "/";
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gItoa(int i)
-{
-       std::stringstream out;
-       out << i;
-       return out.str();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gTrim(const char *f)
-{
-       std::string out = f;
-       return gTrim(out);
-}
-
-
-std::string gTrim(const std::string &s)
-{
-       std::size_t first = s.find_first_not_of(" \n\t");
-       std::size_t last  = s.find_last_not_of(" \n\t");
-       return s.substr(first, last-first+1);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gReplace(std::string in, const std::string& search, const std::string& replace)
-{
-       size_t pos = 0;
-       while ((pos = in.find(search, pos)) != std::string::npos) {
-               in.replace(pos, search.length(), replace);
-               pos += replace.length();
-       }
-       return in;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gStripFileUrl(const char *f)
-{
-       std::string out = f;
-       out = gReplace(out, "file://", "");
-       out = gReplace(out, "%20", " ");
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string gGetHomePath()
-{
-       char path[PATH_MAX];
-
-#if   defined(__linux__)
-
-       snprintf(path, PATH_MAX, "%s/.giada", getenv("HOME"));
-
-#elif defined(_WIN32)
-
-       snprintf(path, PATH_MAX, ".");
-
-#elif defined(__APPLE__)
-
-       struct passwd *p = getpwuid(getuid());
-       if (p == NULL) {
-               gLog("[gGetHomePath] unable to fetch user infos\n");
-               return "";
-       }
-       else {
-               const char *home = p->pw_dir;
-               snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada", home);
-       }
-
-#endif
-
-       return std::string(path);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSplit(std::string in, std::string sep, gVector<std::string> *v)
-{
-       std::string full  = in;
-       std::string token = "";
-       size_t curr = 0;
-       size_t next = -1;
-       do {
-         curr  = next + 1;
-         next  = full.find_first_of(sep, curr);
-               token = full.substr(curr, next - curr);
-               if (token != "")
-                       v->add(token);
-       }
-       while (next != std::string::npos);
-}
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644 (file)
index 0c1a2d0..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef UTILS_H
-#define UTILS_H
-
-
-#include <string>
-#include <cstdio>
-#include "log.h"
-
-
-/* gVector
- * lightweight template class. */
-
-template <class T> class gVector
-{
-public:
-
-       /* gVector()
-        * default constructor, no parameters */
-
-       gVector() : size(0), s(NULL) {}
-
-       /* gVector(const &)
-        * copy-constructor, when gVector a = b (where b is gVector).
-        * Default constructor doesn't copy referenced ojbects, so we need
-        * to re-allocate the internal stack for the copied object */
-
-       gVector(const gVector &other)
-       {
-               s = new T[other.size];
-               for (unsigned i=0; i<other.size; i++)
-                       s[i] = other.s[i];
-               size = other.size;
-       }
-
-
-       ~gVector()
-       {
-               /// FIXME empty s with clear()?!?
-       }
-
-
-       void add(const T &item)
-       {
-               T *tmp = new T[size+1];  /// TODO: chunk increment (size+N), N ~= 16
-               for (unsigned i=0; i<size; i++)
-                       tmp[i] = s[i];
-               tmp[size] = item;
-               delete[] s;
-               s = tmp;
-               size++;
-       }
-
-
-       int del(const T &item)
-       {
-               for (unsigned i=0; i<size; i++)
-                       if (s[i] == item)
-                               return del(i);
-               return -1;
-       }
-
-
-       int del(unsigned p)
-       {
-               if (p > size-1) gLog("[vector] del() outside! requested=%d, size=%d\n", p, size);
-               T *tmp = new T[size-1];
-               unsigned i=0;
-               unsigned j=0;
-               while (i<size) {
-                       if (i != p) {
-                               tmp[j] = s[i];
-                               j++;
-                       }
-                       i++;
-               }
-               delete[] s;
-               s = tmp;
-               size -= 1;
-               return size;
-       }
-
-
-       void clear()
-       {
-               if (size > 0) {
-                       delete [] s;
-                       s = NULL;
-                       size = 0;
-               }
-       }
-
-
-       void swap(unsigned x, unsigned y)
-       {
-               T tmp = s[x];
-               s[x] = s[y];
-               s[y] = tmp;
-       }
-
-
-       T &at(unsigned p)
-       {
-               if (p > size-1) gLog("[vector] at() outside! requested=%d, size=%d\n", p, size);
-               return s[p];
-       }
-
-
-       T &last()
-       {
-               return s[size-1];
-       }
-
-
-       unsigned size;
-       T *s;                           // stack (array of T)
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gFileExists(const char *path);
-
-bool gDirExists(const char *path);
-
-bool gIsDir(const char *path);
-
-bool gIsProject(const char *path);
-
-bool gIsPatch(const char *path);
-
-bool gMkdir(const char *path);
-
-std::string gBasename(const char *path);
-
-std::string gReplace(std::string in, const std::string& search, const std::string& replace);
-
-std::string gDirname(const char *path);
-
-std::string gTrim(const char *path);
-std::string gTrim(const std::string &s);
-
-std::string gGetCurrentPath();
-
-std::string gGetHomePath();
-
-std::string gStripFileUrl(const char *path);
-
-std::string gGetExt(const char *path);
-
-std::string gStripExt(const char *path);
-
-std::string gGetProjectName(const char *path);
-
-std::string gGetSlash();
-
-std::string gItoa(int i);
-
-void gSplit(std::string in, std::string sep, gVector<std::string> *v);
-
-#endif
diff --git a/src/utils/gui_utils.cpp b/src/utils/gui_utils.cpp
new file mode 100644 (file)
index 0000000..7625576
--- /dev/null
@@ -0,0 +1,210 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gui_utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../core/mixer.h"
+#include "../core/patch.h"
+#include "../core/recorder.h"
+#include "../core/wave.h"
+#include "../core/pluginHost.h"
+#include "../core/channel.h"
+#include "../core/conf.h"
+#include "../core/graphics.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_actionEditor.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "../gui/elems/ge_window.h"
+#include "../gui/elems/ge_channel.h"
+#include "gui_utils.h"
+#include "log.h"
+
+
+extern Mixer          G_Mixer;
+extern unsigned      G_beats;
+extern bool                 G_audio_status;
+extern Patch         G_patch;
+extern Conf          G_conf;
+extern uint32_t      G_time;
+extern gdMainWindow *mainWin;
+#ifdef WITH_VST
+extern PluginHost               G_PluginHost;
+#endif
+
+
+static int blinker = 0;
+
+
+void gu_refresh()
+{
+       Fl::lock();
+
+       /* update dynamic elements: in and out meters, beat meter and
+        * each channel */
+
+       mainWin->inOut->refresh();
+       mainWin->beatMeter->redraw();
+       mainWin->keyboard->refreshColumns();
+
+       /* compute timer for blinker */
+
+       blinker++;
+       if (blinker > 12)
+               blinker = 0;
+
+       /* redraw GUI */
+
+       Fl::unlock();
+       Fl::awake();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gu_getBlinker()
+{
+       return blinker;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_updateControls()
+{
+       for (unsigned i=0; i<G_Mixer.channels.size; i++)
+               G_Mixer.channels.at(i)->guiChannel->update();
+
+       mainWin->inOut->setOutVol(G_Mixer.outVol);
+       mainWin->inOut->setInVol(G_Mixer.inVol);
+#ifdef WITH_VST
+       mainWin->inOut->setMasterFxOutFull(G_PluginHost.masterOut.size > 0);
+       mainWin->inOut->setMasterFxInFull(G_PluginHost.masterIn.size > 0);
+#endif
+
+       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
+       mainWin->timing->setBpm(G_Mixer.bpm);
+
+       /* if you reset to init state while the seq is in play: it's better to
+        * update the button status */
+
+       mainWin->controller->updatePlay(G_Mixer.running);
+       mainWin->controller->updateMetronome(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_update_win_label(const char *c)
+{
+       std::string out = VERSIONE_STR;
+       out += " - ";
+       out += c;
+       mainWin->copy_label(out.c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_setFavicon(Fl_Window *w)
+{
+#if defined(__linux__)
+       fl_open_display();
+       Pixmap p, mask;
+       XpmCreatePixmapFromData(
+               fl_display,
+               DefaultRootWindow(fl_display),
+               (char **)giada_icon,
+               &p,
+               &mask,
+               NULL);
+       w->icon((char *)p);
+#elif defined(_WIN32)
+       w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_openSubWindow(gWindow *parent, gWindow *child, int id)
+{
+       if (parent->hasWindow(id)) {
+               gLog("[GU] parent has subwindow with id=%d, deleting\n", id);
+               parent->delSubWindow(id);
+       }
+       child->setId(id);
+       parent->addSubWindow(child);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_refreshActionEditor()
+{
+       /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */
+
+       gdActionEditor *aeditor = (gdActionEditor*) mainWin->getChild(WID_ACTION_EDITOR);
+       if (aeditor) {
+               Channel *chan = aeditor->chan;
+               mainWin->delSubWindow(WID_ACTION_EDITOR);
+               gu_openSubWindow(mainWin, new gdActionEditor(chan), WID_ACTION_EDITOR);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gWindow *gu_getSubwindow(gWindow *parent, int id)
+{
+       if (parent->hasWindow(id))
+               return parent->getChild(id);
+       else
+               return NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_closeAllSubwindows()
+{
+       /* don't close WID_FILE_BROWSER, because it's the caller of this
+        * function */
+
+       mainWin->delSubWindow(WID_ACTION_EDITOR);
+       mainWin->delSubWindow(WID_SAMPLE_EDITOR);
+       mainWin->delSubWindow(WID_FX_LIST);
+       mainWin->delSubWindow(WID_FX);
+}
diff --git a/src/utils/gui_utils.h b/src/utils/gui_utils.h
new file mode 100644 (file)
index 0000000..66156ce
--- /dev/null
@@ -0,0 +1,93 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gui_utils
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef GUI_UTILS_H
+#define GUI_UTILS_H
+
+#include <dirent.h>
+#include <string>
+#include <FL/x.H>
+#include <FL/Fl.H>
+#ifdef __APPLE__
+       #include <libgen.h>     // in osx, for basename() (but linux?)
+#endif
+
+/* including stuff for the favicon */
+
+#if defined(_WIN32)
+       #include "../ext/resource.h"
+#elif defined(__linux__)
+       #include <X11/xpm.h>
+#endif
+
+
+/* refresh
+ * refresh all GUI elements. */
+
+void gu_refresh();
+
+/* getBlinker
+*  return blinker value, used to make widgets blink. */
+
+int gu_getBlinker();
+
+/* updateControls
+ * update attributes of control elements (sample names, volumes, ...).
+ * Useful when loading a new patch. */
+
+void gu_updateControls();
+
+/* update_win_label
+ * update the name of the main window */
+
+void gu_update_win_label(const char *c);
+
+void gu_setFavicon(Fl_Window *w);
+
+void gu_openSubWindow(class gWindow *parent, gWindow *child, int id);
+
+/* refreshActionEditor
+ * reload the action editor window by closing and reopening it. It's used
+ * when you delete some actions from the mainWindow and the action editor
+ * window is open. */
+
+void gu_refreshActionEditor();
+
+
+/* closeAllSubwindows
+ * close all subwindows attached to mainWin. */
+
+void gu_closeAllSubwindows();
+
+
+/* getSubwindow
+ * return a pointer to an open subwindow, otherwise NULL. */
+
+gWindow *gu_getSubwindow(class gWindow *parent, int id);
+
+#endif
diff --git a/src/utils/log.cpp b/src/utils/log.cpp
new file mode 100644 (file)
index 0000000..9b2182d
--- /dev/null
@@ -0,0 +1,80 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * log
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <cstdio>
+#include <cstdarg>
+#include <string>
+#include "../utils/utils.h"
+#include "../core/const.h"
+#include "log.h"
+
+
+static FILE *f;
+static int   mode;
+static bool  stat;
+
+
+int gLog_init(int m) {
+       mode = m;
+       stat = true;
+       if (mode == LOG_MODE_FILE) {
+               std::string fpath = gGetHomePath() + "/giada.log";
+               f = fopen(fpath.c_str(), "a");
+               if (!f) {
+                       stat = false;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gLog_close() {
+       if (mode == LOG_MODE_FILE)
+               fclose(f);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void gLog(const char *format, ...) {
+       if (mode == LOG_MODE_MUTE)
+               return;
+  va_list args;
+  va_start(args, format);
+  if (mode == LOG_MODE_FILE && stat == true)
+               vfprintf(f, format, args);
+  else
+               vprintf(format, args);
+  va_end(args);
+}
diff --git a/src/utils/log.h b/src/utils/log.h
new file mode 100644 (file)
index 0000000..c53f9c7
--- /dev/null
@@ -0,0 +1,45 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * log
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+
+/* init
+ * init logger. Mode defines where to write the output: LOG_MODE_STDOUT,
+ * LOG_MODE_FILE and LOG_MODE_MUTE. */
+int  gLog_init (int mode);
+
+void gLog_close();
+
+void gLog(const char *format, ...);
+
+
+#endif
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
new file mode 100644 (file)
index 0000000..e7b2e8c
--- /dev/null
@@ -0,0 +1,379 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "utils.h"
+#if defined(_WIN32)                    // getcwd (unix) or __getcwd (win)
+       #include <direct.h>
+       #include <windows.h>
+#else
+       #include <unistd.h>
+#endif
+
+#include <cstdarg>
+#include <sys/stat.h>   // stat (gDirExists)
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <string.h>
+#include <sstream>
+#include <limits.h>
+#if defined(__APPLE__)
+       #include <libgen.h>     // basename unix
+       #include <pwd.h>        // getpwuid
+#endif
+
+
+
+bool gFileExists(const char *filename) {
+       FILE *fh = fopen(filename, "rb");
+       if (!fh) {
+               return 0;
+       }
+       else {
+               fclose(fh);
+               return 1;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gIsDir(const char *path)
+{
+       bool ret;
+
+#if defined(__linux__)
+
+       struct stat s1;
+       stat(path, &s1);
+       ret = S_ISDIR(s1.st_mode);
+
+#elif defined(__APPLE__)
+
+       if (strcmp(path, "")==0)
+               ret = false;
+       else {
+               struct stat s1;
+               stat(path, &s1);
+               ret = S_ISDIR(s1.st_mode);
+
+               /* check if ret is a bundle, a special OS X folder which must be
+                * shown as a regular file (VST).
+                * FIXME - consider native functions CFBundle... */
+
+               if (ret) {
+                       std::string tmp = path;
+                       tmp += "/Contents/Info.plist";
+                       if (gFileExists(tmp.c_str()))
+                               ret = false;
+               }
+       }
+
+#elif defined(__WIN32)
+
+  unsigned dwAttrib = GetFileAttributes(path);
+  ret = (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+        (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
+#endif
+
+       return ret & !gIsProject(path);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gDirExists(const char *path)
+{
+       struct stat st;
+       if (stat(path, &st) != 0 && errno == ENOENT)
+               return false;
+       return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gMkdir(const char *path)
+{
+#if defined(__linux__) || defined(__APPLE__)
+       if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
+#else
+       if (_mkdir(path) == 0)
+#endif
+               return true;
+       return false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gBasename(const char *path)
+{
+       std::string out = path;
+       out.erase(0, out.find_last_of(gGetSlash().c_str())+1);
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gDirname(const char *path)
+{
+       std::string out = path;
+       out.erase(out.find_last_of(gGetSlash().c_str()));
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gGetCurrentPath()
+{
+ char buf[PATH_MAX];
+#if defined(__WIN32)
+       if (_getcwd(buf, PATH_MAX) != NULL)
+#else
+       if (getcwd(buf, PATH_MAX) != NULL)
+#endif
+               return buf;
+       else
+               return "";
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gGetExt(const char *file)
+{
+       int len = strlen(file);
+       int pos = len;
+       while (pos>0) {
+               if (file[pos] == '.')
+                       break;
+               pos--;
+       }
+       if (pos==0)
+               return "";
+       std::string out = file;
+       return out.substr(pos+1, len);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gStripExt(const char *file)
+{
+       int len = strlen(file);
+       int pos = -1;
+       for (int i=0; i<len; i++)
+               if (file[i] == '.') {
+                       pos = i;
+                       break;
+               }
+       std::string out = file;
+       return pos == -1 ? out : out.substr(0, pos);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gIsProject(const char *path)
+{
+       /** FIXME - checks too weak */
+
+       if (gGetExt(path) == "gprj" && gDirExists(path))
+               return 1;
+       return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gIsPatch(const char *path)
+{
+       if (gGetExt(path) == "gptc")
+               return 1;
+       return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gGetProjectName(const char *path)
+{
+       std::string out;
+       out = gStripExt(path);
+
+       int i = out.size();
+       while (i>=0) { /// TODO - use gGetSlash()
+#if defined(__linux__) || defined(__APPLE__)
+               if (out[i] == '/')
+#elif defined(_WIN32)
+               if (out[i] == '\\')
+#endif
+                       break;
+               i--;
+       }
+
+       out.erase(0, i+1);      // includes the '/' (or '\' on windows)
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gGetSlash() // TODO - create SLASH macro or constant
+{
+#if defined(_WIN32)
+       return "\\";
+#else
+       return "/";
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gItoa(int i)
+{
+       std::stringstream out;
+       out << i;
+       return out.str();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gTrim(const char *f)
+{
+       std::string out = f;
+       return gTrim(out);
+}
+
+
+std::string gTrim(const std::string &s)
+{
+       std::size_t first = s.find_first_not_of(" \n\t");
+       std::size_t last  = s.find_last_not_of(" \n\t");
+       return s.substr(first, last-first+1);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gReplace(std::string in, const std::string& search, const std::string& replace)
+{
+       size_t pos = 0;
+       while ((pos = in.find(search, pos)) != std::string::npos) {
+               in.replace(pos, search.length(), replace);
+               pos += replace.length();
+       }
+       return in;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gStripFileUrl(const char *f)
+{
+       std::string out = f;
+       out = gReplace(out, "file://", "");
+       out = gReplace(out, "%20", " ");
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string gGetHomePath()
+{
+       char path[PATH_MAX];
+
+#if   defined(__linux__)
+
+       snprintf(path, PATH_MAX, "%s/.giada", getenv("HOME"));
+
+#elif defined(_WIN32)
+
+       snprintf(path, PATH_MAX, ".");
+
+#elif defined(__APPLE__)
+
+       struct passwd *p = getpwuid(getuid());
+       if (p == NULL) {
+               gLog("[gGetHomePath] unable to fetch user infos\n");
+               return "";
+       }
+       else {
+               const char *home = p->pw_dir;
+               snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada", home);
+       }
+
+#endif
+
+       return std::string(path);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gSplit(std::string in, std::string sep, gVector<std::string> *v)
+{
+       std::string full  = in;
+       std::string token = "";
+       size_t curr = 0;
+       size_t next = -1;
+       do {
+         curr  = next + 1;
+         next  = full.find_first_of(sep, curr);
+               token = full.substr(curr, next - curr);
+               if (token != "")
+                       v->add(token);
+       }
+       while (next != std::string::npos);
+}
diff --git a/src/utils/utils.h b/src/utils/utils.h
new file mode 100644 (file)
index 0000000..0c1a2d0
--- /dev/null
@@ -0,0 +1,190 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef UTILS_H
+#define UTILS_H
+
+
+#include <string>
+#include <cstdio>
+#include "log.h"
+
+
+/* gVector
+ * lightweight template class. */
+
+template <class T> class gVector
+{
+public:
+
+       /* gVector()
+        * default constructor, no parameters */
+
+       gVector() : size(0), s(NULL) {}
+
+       /* gVector(const &)
+        * copy-constructor, when gVector a = b (where b is gVector).
+        * Default constructor doesn't copy referenced ojbects, so we need
+        * to re-allocate the internal stack for the copied object */
+
+       gVector(const gVector &other)
+       {
+               s = new T[other.size];
+               for (unsigned i=0; i<other.size; i++)
+                       s[i] = other.s[i];
+               size = other.size;
+       }
+
+
+       ~gVector()
+       {
+               /// FIXME empty s with clear()?!?
+       }
+
+
+       void add(const T &item)
+       {
+               T *tmp = new T[size+1];  /// TODO: chunk increment (size+N), N ~= 16
+               for (unsigned i=0; i<size; i++)
+                       tmp[i] = s[i];
+               tmp[size] = item;
+               delete[] s;
+               s = tmp;
+               size++;
+       }
+
+
+       int del(const T &item)
+       {
+               for (unsigned i=0; i<size; i++)
+                       if (s[i] == item)
+                               return del(i);
+               return -1;
+       }
+
+
+       int del(unsigned p)
+       {
+               if (p > size-1) gLog("[vector] del() outside! requested=%d, size=%d\n", p, size);
+               T *tmp = new T[size-1];
+               unsigned i=0;
+               unsigned j=0;
+               while (i<size) {
+                       if (i != p) {
+                               tmp[j] = s[i];
+                               j++;
+                       }
+                       i++;
+               }
+               delete[] s;
+               s = tmp;
+               size -= 1;
+               return size;
+       }
+
+
+       void clear()
+       {
+               if (size > 0) {
+                       delete [] s;
+                       s = NULL;
+                       size = 0;
+               }
+       }
+
+
+       void swap(unsigned x, unsigned y)
+       {
+               T tmp = s[x];
+               s[x] = s[y];
+               s[y] = tmp;
+       }
+
+
+       T &at(unsigned p)
+       {
+               if (p > size-1) gLog("[vector] at() outside! requested=%d, size=%d\n", p, size);
+               return s[p];
+       }
+
+
+       T &last()
+       {
+               return s[size-1];
+       }
+
+
+       unsigned size;
+       T *s;                           // stack (array of T)
+};
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool gFileExists(const char *path);
+
+bool gDirExists(const char *path);
+
+bool gIsDir(const char *path);
+
+bool gIsProject(const char *path);
+
+bool gIsPatch(const char *path);
+
+bool gMkdir(const char *path);
+
+std::string gBasename(const char *path);
+
+std::string gReplace(std::string in, const std::string& search, const std::string& replace);
+
+std::string gDirname(const char *path);
+
+std::string gTrim(const char *path);
+std::string gTrim(const std::string &s);
+
+std::string gGetCurrentPath();
+
+std::string gGetHomePath();
+
+std::string gStripFileUrl(const char *path);
+
+std::string gGetExt(const char *path);
+
+std::string gStripExt(const char *path);
+
+std::string gGetProjectName(const char *path);
+
+std::string gGetSlash();
+
+std::string gItoa(int i);
+
+void gSplit(std::string in, std::string sep, gVector<std::string> *v);
+
+#endif
diff --git a/src/wave.cpp b/src/wave.cpp
deleted file mode 100644 (file)
index edaef7b..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * wave
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>  // memcpy
-#include <math.h>
-#include "wave.h"
-#include "utils.h"
-#include "conf.h"
-#include "init.h"
-#include "log.h"
-
-
-extern Conf G_Conf;
-
-
-Wave::Wave()
-       : data     (NULL),
-               size     (0),
-               isLogical(0),
-               isEdited (0) {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-Wave::~Wave() {
-       clear();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Wave::open(const char *f) {
-
-       pathfile = f;
-       name     = gStripExt(gBasename(f).c_str());
-       fileIn   = sf_open(f, SFM_READ, &inHeader);
-
-       if (fileIn == NULL) {
-               gLog("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn));
-               pathfile = "";
-               name     = "";
-               return 0;
-       }
-
-       isLogical = false;
-       isEdited  = false;
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-/* how to read and write with libsndfile:
- *
- * a frame consists of all items (samples) that belong to the same
- * point in time. So in each frame there are as many items as there
- * are channels.
- *
- * Quindi:
- *     frame  = [item, item, ...]
- * In pratica:
- *  frame1 = [itemLeft, itemRight]
- *     frame2 = [itemLeft, itemRight]
- *     ...
- */
-
-int Wave::readData() {
-       size = inHeader.frames * inHeader.channels;
-       data = (float *) malloc(size * sizeof(float));
-       if (data == NULL) {
-               gLog("[wave] unable to allocate memory\n");
-               return 0;
-       }
-
-       if (sf_read_float(fileIn, data, size) != size)
-               gLog("[wave] warning: incomplete read!\n");
-
-       sf_close(fileIn);
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Wave::writeData(const char *f) {
-
-       /* prepare the header for output file */
-
-       outHeader.samplerate = inHeader.samplerate;
-       outHeader.channels   = inHeader.channels;
-       outHeader.format     = inHeader.format;
-
-       fileOut = sf_open(f, SFM_WRITE, &outHeader);
-       if (fileOut == NULL) {
-               gLog("[wave] unable to open %s for exporting\n", f);
-               return 0;
-       }
-
-       int out = sf_write_float(fileOut, data, size);
-       if (out != (int) size) {
-               gLog("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut));
-               return 0;
-       }
-
-       isLogical = false;
-       isEdited  = false;
-       sf_close(fileOut);
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Wave::clear() {
-       if (data != NULL) {
-               free(data);
-               data     = NULL;
-               pathfile = "";
-               size     = 0;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Wave::allocEmpty(unsigned __size) {
-
-       /* the caller must pass a __size for stereo values */
-
-       /// FIXME - this way if malloc fails size becomes wrong
-       size = __size;
-       data = (float *) malloc(size * sizeof(float));
-       if (data == NULL) {
-               gLog("[wave] unable to allocate memory\n");
-               return 0;
-       }
-
-       memset(data, 0, sizeof(float) * size); /// FIXME - is it useful?
-
-       inHeader.samplerate = G_Conf.samplerate;
-       inHeader.channels   = 2;
-       inHeader.format     = SF_FORMAT_WAV | SF_FORMAT_FLOAT; // wave only
-
-       isLogical = true;
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int Wave::resample(int quality, int newRate) {
-
-       float ratio = newRate / (float) inHeader.samplerate;
-       int newSize = ceil(size * ratio);
-       if (newSize % 2 != 0)   // libsndfile goes crazy with odd size in case of saving
-               newSize++;
-
-       float *tmp = (float *) malloc(newSize * sizeof(float));
-       if (!tmp) {
-               gLog("[wave] unable to allocate memory for resampling\n");
-               return -1;
-       }
-
-       SRC_DATA src_data;
-       src_data.data_in       = data;
-       src_data.input_frames  = size/2;     // in frames, i.e. /2 (stereo)
-       src_data.data_out      = tmp;
-       src_data.output_frames = newSize/2;  // in frames, i.e. /2 (stereo)
-       src_data.src_ratio     = ratio;
-
-       gLog("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2);
-
-       int ret = src_simple(&src_data, quality, 2);
-       if (ret != 0) {
-               gLog("[wave] resampling error: %s\n", src_strerror(ret));
-               return 0;
-       }
-
-       free(data);
-       data = tmp;
-       size = newSize;
-       inHeader.samplerate = newRate;
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-std::string Wave::basename() {
-       return gStripExt(gBasename(pathfile.c_str()).c_str());
-}
-
-std::string Wave::extension() {
-       return gGetExt(pathfile.c_str());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void Wave::updateName(const char *n) {
-       std::string ext = gGetExt(pathfile.c_str());
-       name      = gStripExt(gBasename(n).c_str());
-       pathfile  = gDirname(pathfile.c_str()) + gGetSlash() + name + "." + ext;
-       isLogical = true;
-
-       /* a wave with updated name must become logical, since the underlying
-        * file does not exist yet. */
-}
diff --git a/src/wave.h b/src/wave.h
deleted file mode 100644 (file)
index 9ce81df..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * wave
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef WAVE_H
-#define WAVE_H
-
-
-#include <samplerate.h>
-#include <sndfile.h>
-#include <string>
-
-
-class Wave {
-
-private:
-
-       SNDFILE   *fileIn;
-       SNDFILE   *fileOut;
-       SF_INFO    inHeader;
-       SF_INFO    outHeader;
-
-public:
-
-       Wave();
-       ~Wave();
-
-       std::string pathfile; // full path + sample name
-       std::string name;                       // sample name (changeable)
-
-       float     *data;
-       int        size;                          // wave size (size in stereo: size / 2)
-       bool       isLogical;   // memory only (a take)
-       bool       isEdited;    // edited via editor
-
-       inline int  rate    () { return inHeader.samplerate; }
-       inline int  channels() { return inHeader.channels; }
-       inline int  frames  () { return inHeader.frames; }
-       inline void rate    (int v) { inHeader.samplerate = v; }
-       inline void channels(int v) { inHeader.channels = v; }
-       inline void frames  (int v) { inHeader.frames = v; }
-
-       std::string basename ();
-       std::string extension();
-
-       void updateName(const char *n);
-       int  open      (const char *f);
-       int  readData  ();
-       int      writeData (const char *f);
-       void clear     ();
-
-       /* allocEmpty
-        * alloc an empty waveform. */
-
-       int allocEmpty(unsigned size);
-
-       /* resample
-        * simple algorithm for one-shot resampling. */
-
-       int resample(int quality, int newRate);
-};
-
-#endif
diff --git a/src/waveFx.cpp b/src/waveFx.cpp
deleted file mode 100644 (file)
index 25e0812..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * waveFx
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <math.h>
-#include "waveFx.h"
-#include "channel.h"
-#include "mixer.h"
-#include "wave.h"
-#include "log.h"
-
-
-extern Mixer G_Mixer;
-
-
-float wfx_normalizeSoft(Wave *w) {
-       float peak = 0.0f;
-       float abs  = 0.0f;
-       for (int i=0; i<w->size; i++) { // i++: both L and R samples
-               abs = fabs(w->data[i]);
-               if (abs > peak)
-                       peak = abs;
-       }
-
-       /* peak == 0.0f: don't normalize the silence
-        * peak > 1.0f: don't reduce the amplitude, just leave it alone */
-
-       if (peak == 0.0f || peak > 1.0f)
-               return 1.0f;
-
-       return 1.0f / peak;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool wfx_monoToStereo(Wave *w) {
-
-       unsigned newSize = w->size * 2;
-       float *dataNew = (float *) malloc(newSize * sizeof(float));
-       if (dataNew == NULL) {
-               gLog("[wfx] unable to allocate memory for mono>stereo conversion\n");
-               return 0;
-       }
-
-       for (int i=0, j=0; i<w->size; i++) {
-               dataNew[j]   = w->data[i];
-               dataNew[j+1] = w->data[i];
-               j+=2;
-       }
-
-       free(w->data);
-       w->data = dataNew;
-       w->size = newSize;
-       w->frames(w->frames()*2);
-       w->channels(2);
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void wfx_silence(Wave *w, int a, int b) {
-
-       /* stereo values */
-       a = a * 2;
-       b = b * 2;
-
-       gLog("[wfx] silencing from %d to %d\n", a, b);
-
-       for (int i=a; i<b; i+=2) {
-               w->data[i]   = 0.0f;
-               w->data[i+1] = 0.0f;
-       }
-
-       w->isEdited = true;
-
-       return;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int wfx_cut(Wave *w, int a, int b) {
-       a = a * 2;
-       b = b * 2;
-
-       if (a < 0) a = 0;
-       if (b > w->size) b = w->size;
-
-       /* create a new temp wave and copy there the original one, skipping
-        * the a-b range */
-
-       unsigned newSize = w->size-(b-a);
-       float *temp = (float *) malloc(newSize * sizeof(float));
-       if (temp == NULL) {
-               gLog("[wfx] unable to allocate memory for cutting\n");
-               return 0;
-       }
-
-       gLog("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2);
-
-       for (int i=0, k=0; i<w->size; i++) {
-               if (i < a || i >= b) {                         // left margin always included, in order to keep
-                       temp[k] = w->data[i];   // the stereo pair
-                       k++;
-               }
-       }
-
-       free(w->data);
-       w->data = temp;
-       w->size = newSize;
-       //w->inHeader.frames -= b-a;
-       w->frames(w->frames() - b - a);
-       w->isEdited = true;
-
-       gLog("[wfx] cutting done\n");
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int wfx_trim(Wave *w, int a, int b) {
-       a = a * 2;
-       b = b * 2;
-
-       if (a < 0) a = 0;
-       if (b > w->size) b = w->size;
-
-       int newSize = b - a;
-       float *temp = (float *) malloc(newSize * sizeof(float));
-       if (temp == NULL) {
-               gLog("[wfx] unable to allocate memory for trimming\n");
-               return 0;
-       }
-
-       gLog("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a);
-
-       for (int i=a, k=0; i<b; i++, k++)
-               temp[k] = w->data[i];
-
-       free(w->data);
-       w->data = temp;
-       w->size = newSize;
-       //w->inHeader.frames = b-a;
-       w->frames(b - a);
-       w->isEdited = true;
-
-       return 1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void wfx_fade(Wave *w, int a, int b, int type) {
-
-       float m = type == 0 ? 0.0f : 1.0f;
-       float d = 1.0f/(float)(b-a);
-       if (type == 1)
-               d = -d;
-
-       a *= 2;
-       b *= 2;
-
-       for (int i=a; i<b; i+=2) {
-               w->data[i]   *= m;
-               w->data[i+1] *= m;
-               m += d;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void wfx_smooth(Wave *w, int a, int b) {
-
-       int d = 32;  // 64 if stereo data
-
-       /* do nothing if fade edges (both of 32 samples) are > than selected
-        * portion of wave. d*2 => count both edges, (b-a)*2 => stereo
-        * values. */
-
-       if (d*2 > (b-a)*2) {
-               gLog("[WFX] selection is too small, nothing to do\n");
-               return;
-       }
-
-       wfx_fade(w, a, a+d, 0);
-       wfx_fade(w, b-d, b, 1);
-}
diff --git a/src/waveFx.h b/src/waveFx.h
deleted file mode 100644 (file)
index ebdef4a..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * waveFx
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef WAVEFX_H
-#define WAVEFX_H
-
-
-/* normalizeSoft
- * normalize the wave by returning the dB value for the boost volume. It
- * doesn't deal with data in memory. */
-
-float wfx_normalizeSoft(class Wave *w);
-
-bool wfx_monoToStereo(class Wave *w);
-
-void wfx_silence(class Wave *w, int a, int b);
-
-int wfx_cut(class Wave *w, int a, int b);
-
-int wfx_trim(class Wave *w, int a, int b);
-
-/* fade
- * fade in or fade out selection. Fade In = type 0, Fade Out = type 1 */
-
-void wfx_fade(class Wave *w, int a, int b, int type);
-
-/* smooth
- * smooth edges of selection. */
-
-void wfx_smooth(class Wave *w, int a, int b);
-
-
-#endif